diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..6ff14b62 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +.history +.project +.settings +.vscode +build +dist +coverage +node_modules +npm-debug.log +package-lock.json +src/events +integ-test-results +.DS_Store +*.swp +chromedriver.log +geckodriver.log +safaridriver.log +tests_output diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..f6c518cb --- /dev/null +++ b/.prettierignore @@ -0,0 +1,6 @@ +build +dist +coverage +src/events +package-lock.json +.vscode diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 00000000..1661de8f --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "trailingComma": "none", + "tabWidth": 4, + "semi": true, + "singleQuote": true +} diff --git a/.testcaferc.json b/.testcaferc.json new file mode 100644 index 00000000..978bc2c5 --- /dev/null +++ b/.testcaferc.json @@ -0,0 +1,28 @@ +{ + "screenshotPath": "build/brazil-integration-tests/", + "screenshotPathPattern": "failed_test_${TEST_INDEX}/${BROWSER}/${FILE_INDEX}.png", + "takeScreenshotsOnFails": true, + "assertionTimeout": 6000, + "src": "src/**/__integ__/**/*.(js|ts)", + "skipJsErrors": true, + "browsers": { + "path": "/apollo/env/DiamondToolkitBrowsersEnvironment/bin/firefox", + "cmd": "--headless" + }, + "reporter": [ + { + "name": "spec" + }, + { + "name": "html", + "output": "build/brazil-integration-tests/index.html" + }, + { + "name": "json", + "output": "build/brazil-integration-tests/report.json" + } + ], + "compilerOptions": { + "typescript": { "customCompilerModulePath": "../typescript" } + } +} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 5b627cfa..ec98f2b7 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,4 +1,5 @@ ## Code of Conduct + This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact opensource-codeofconduct@amazon.com with any additional questions or comments. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c4b6a1c5..c631ac19 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,6 @@ documentation, we greatly value feedback and contributions from our community. Please read through this document before submitting any issues or pull requests to ensure we have all the necessary information to effectively respond to your bug report or contribution. - ## Reporting Bugs/Feature Requests We welcome you to use the GitHub issue tracker to report bugs or suggest features. @@ -14,16 +13,16 @@ We welcome you to use the GitHub issue tracker to report bugs or suggest feature When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: -* A reproducible test case or series of steps -* The version of our code being used -* Any modifications you've made relevant to the bug -* Anything unusual about your environment or deployment - +- A reproducible test case or series of steps +- The version of our code being used +- Any modifications you've made relevant to the bug +- Anything unusual about your environment or deployment ## Contributing via Pull Requests + Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: -1. You are working against the latest source on the *main* branch. +1. You are working against the latest source on the _main_ branch. 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. @@ -39,20 +38,19 @@ To send us a pull request, please: GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). - ## Finding contributions to work on -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. +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. ## Code of Conduct + This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact opensource-codeofconduct@amazon.com with any additional questions or comments. - ## Security issue notifications -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. +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. ## Licensing diff --git a/LICENSE-THIRD-PARTY b/LICENSE-THIRD-PARTY new file mode 100644 index 00000000..8891e143 --- /dev/null +++ b/LICENSE-THIRD-PARTY @@ -0,0 +1,11427 @@ +@aws-crypto/ie11-detection +1.0.0 + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@aws-crypto/sha256-browser +1.1.0 + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@aws-crypto/sha256-js +1.1.0 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-crypto/supports-web-crypto +1.0.0 + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@aws-sdk/abort-controller +3.6.1 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/client-cognito-identity +3.7.0 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@aws-sdk/client-sso +3.7.0 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@aws-sdk/client-sts +3.11.0 +Apache-2.0 + +****************************** + +@aws-sdk/config-resolver +3.7.0 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/credential-provider-cognito-identity +3.7.0 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@aws-sdk/credential-provider-env +3.7.0 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/credential-provider-imds +3.7.0 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/credential-provider-ini +3.7.0 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/credential-provider-node +3.7.0 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/credential-provider-process +3.7.0 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/credential-provider-sso +3.7.0 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/fetch-http-handler +3.6.1 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/hash-node +3.6.1 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/invalid-dependency +3.6.1 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@aws-sdk/is-array-buffer +3.6.1 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/md5-js +3.6.1 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/middleware-content-length +3.6.1 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/middleware-host-header +3.6.1 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@aws-sdk/middleware-logger +3.6.1 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/middleware-retry +3.7.0 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@aws-sdk/middleware-serde +3.6.1 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@aws-sdk/middleware-signing +3.6.1 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/middleware-stack +3.6.1 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/middleware-user-agent +3.6.1 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@aws-sdk/node-config-provider +3.7.0 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/node-http-handler +3.6.1 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/property-provider +3.7.0 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/protocol-http +3.6.1 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@aws-sdk/querystring-builder +3.6.1 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@aws-sdk/querystring-parser +3.6.1 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@aws-sdk/service-error-classification +3.6.1 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@aws-sdk/shared-ini-file-loader +3.7.0 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/signature-v4 +3.6.1 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/smithy-client +3.6.1 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@aws-sdk/types +3.6.1 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/url-parser +3.6.1 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@aws-sdk/url-parser-native +3.6.1 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@aws-sdk/util-base64-browser +3.6.1 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/util-base64-node +3.6.1 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/util-body-length-browser +3.6.1 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/util-body-length-node +3.6.1 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/util-buffer-from +3.6.1 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/util-hex-encoding +3.6.1 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/util-locate-window +3.6.1 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/util-uri-escape +3.6.1 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/util-user-agent-browser +3.6.1 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@aws-sdk/util-user-agent-node +3.7.0 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@aws-sdk/util-utf8-browser +3.6.1 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +@aws-sdk/util-utf8-node +3.6.1 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +****************************** + +bowser +2.11.0 +Copyright 2015, Dustin Diaz (the "Original Author") +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +Distributions of all or part of the Software intended to be used +by the recipients as they would use the unmodified Software, +containing modifications that substantially alter, remove, or +disable functionality of the Software, outside of the documented +configuration mechanisms provided by the Software, shall be +modified such that the Original Author's bug reporting email +addresses and urls are either replaced with the contact information +of the parties responsible for the changes, or removed entirely. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + + +Except where noted, this license applies to any and all software +programs and associated documentation files created by the +Original Author, when distributed with the Software. + + +****************************** + +fast-base64-decode +1.0.0 +license: MIT +authors: Linus Unnebäck + +****************************** + +fast-xml-parser +3.19.0 +MIT License + +Copyright (c) 2017 Amit Kumar Gupta + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +****************************** + +punycode +1.3.2 +license: MIT +authors: Mathias Bynens + +Copyright Mathias Bynens + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +****************************** + +querystring +0.2.0 +MIT License + +Copyright 2012 Irakli Gozalishvili. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + + +****************************** + +react-native-get-random-values +1.6.0 +MIT License + +Copyright (c) 2018, 2020 Linus Unnebäck + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +shimmer +1.2.1 +BSD 2-Clause License + +Copyright (c) 2013-2019, Forrest L Norvell +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +****************************** + +tslib +2.1.0 +Copyright (c) Microsoft Corporation. +BSD Zero Clause License + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +****************************** + +ua-parser-js +0.7.24 +MIT License + +Copyright (c) 2012-2021 Faisal Salman <> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +url +0.11.0 +The MIT License (MIT) + +Copyright Joyent, Inc. and other Node contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +uuid +8.3.2 +The MIT License (MIT) + +Copyright (c) 2010-2020 Robert Kieffer and other contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +****************************** + +web-vitals +1.1.1 + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 Google LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 99313dc1..29cacf63 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,87 @@ -## AWS Real User Monitoring (RUM) Client +# AWS Real User Monitoring (RUM) Web Client -This is the AWS RUM client source code repository which hosts the RUM agent for collecting real time user monitoring events from web clients to send to any AWS monitoring service. +This is the AWS RUM client source code repository which hosts the RUM agent for +collecting real time user monitoring events from web clients to send to any AWS +monitoring service. + +## Installing + +The latest stable version of the RUM Web Client is available from NPM. For local +development, install the SDK in your project directory with npm. + +`npm install aws-rum-web` + +Use the `--save` option to save the SDK as a dependency in your application's `package.json`. + +`npm install aws-rum-web --save` + +## Getting Help + +Use the following community resources for getting help with the SDK. We use the GitHub issues for tracking bugs and feature requests. + +- Ask a question in the [CloudWatch RUM Forum](). +- Open a support ticket with [AWS Support](https://docs.aws.amazon.com/awssupport/latest/user/getting-started.html). +- If you think you may have found a bug, open an [issue](https://github.com/aws-observability/aws-rum-web/issues/new). + +## Opening Issues + +If you encounter a bug with the AWS RUM Web Client, we want to hear about it. +Before opening a new issue, search the existing issues to see if others are also +experiencing the issue. Include the version of the AWS RUM Web Client, Node.js +runtime, and other dependencies if applicable. In addition, include the repro +case when appropriate. + +The GitHub issues are intended for bug reports and feature requests. For help +and questions about using the AWS RUM Web Client, use the resources listed in +the Getting Help section. Keeping the list of open issues lean helps us respond +in a timely manner. + +## Contributing + +We support and accept PRs from the community. + +See [CONTRIBUTING](./CONTRIBUTING.md) + +## Run Tests from Source + +To perform exploratory testing, run the Webpack DevServer: + +`npm run server` + +In a browser, navigate to http://localhost:9000. + +To run (Jest) unit tests: + +`npm run test` + +To run (TestCafe) browser integration tests: + +`npm run integ:local` + +Some plugins perform monkey patching which is incompatible with TestCafe. In +these cases, run Nightwatch as a separate browser integration test target: + +`npm run integ:local:nightwatch` + +## Pre-commit Tasks + +The RUM Web Client uses pre-commit tasks to lint and format its source code. +Before submitting code, check that all linter and formatter warnings have been +resolved. + +Attempt to automatically repair linter warnings: + +`npm run lint:fix` + +Format code: + +`npm run prettier:fix` ## Security -See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. +See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more +information. ## License This project is licensed under the Apache-2.0 License. - diff --git a/app/cookies_disabled.html b/app/cookies_disabled.html new file mode 100644 index 00000000..0de5f56f --- /dev/null +++ b/app/cookies_disabled.html @@ -0,0 +1,83 @@ + + + + RUM Integ Test + + + + + + + + +

This application is used for RUM integ testing.

+
+ + +
+ + + + + + + + + + + + + + + +
Request URL
Request Header
Request Body
+ + + + + + + + + + + + + +
Response Status Code
Response Header
Response Body
+ + diff --git a/app/cookies_enabled.html b/app/cookies_enabled.html new file mode 100644 index 00000000..8ab00467 --- /dev/null +++ b/app/cookies_enabled.html @@ -0,0 +1,83 @@ + + + + RUM Integ Test + + + + + + + + +

This application is used for RUM integ testing.

+
+ + +
+ + + + + + + + + + + + + + + +
Request URL
Request Header
Request Body
+ + + + + + + + + + + + + +
Response Status Code
Response Header
Response Body
+ + diff --git a/app/dom_event.html b/app/dom_event.html new file mode 100644 index 00000000..0ef736e5 --- /dev/null +++ b/app/dom_event.html @@ -0,0 +1,128 @@ + + + + RUM Integ Test + + + + + + + + +

This application is used for RUM integ testing.

+
+ + + + + +
+ + Link One +
+ + +
+ + + + + + + + + + + + + + + +
Request URL
Request Header
Request Body
+ + + + + + + + + + + + + +
Response Status Code
Response Header
Response Body
+ + diff --git a/app/http_fetch_event.html b/app/http_fetch_event.html new file mode 100644 index 00000000..461642c6 --- /dev/null +++ b/app/http_fetch_event.html @@ -0,0 +1,122 @@ + + + + RUM Integ Test + + + + + + + + + + + +

This application is used for RUM integ testing.

+
+ + + + +
+ + +
+ + + + + + + + + + + + + + + +
Request URL
Request Header
Request Body
+ + + + + + + + + + + + + +
Response Status Code
Response Header
Response Body
+ + diff --git a/app/http_xhr_event.html b/app/http_xhr_event.html new file mode 100644 index 00000000..2701bc1e --- /dev/null +++ b/app/http_xhr_event.html @@ -0,0 +1,152 @@ + + + + RUM Integ Test + + + + + + + + + +

This application is used for RUM integ testing.

+
+ + + + +
+ + +
+ + + + + + + + + + + + + + + +
Request URL
Request Header
Request Body
+ + + + + + + + + + + + + +
Response Status Code
Response Header
Response Body
+ + diff --git a/app/index.html b/app/index.html new file mode 100644 index 00000000..554af014 --- /dev/null +++ b/app/index.html @@ -0,0 +1,130 @@ + + + + RUM Integ Test + + + + + + + + + +

This application is used for RUM integ testing.

+
+ +

+ +

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
Request URL
Request Header
Request Body
+ + + + + + + + + + + + + +
Response Status Code
Response Header
Response Body
+ + diff --git a/app/js_error_event.html b/app/js_error_event.html new file mode 100644 index 00000000..9f8f5c83 --- /dev/null +++ b/app/js_error_event.html @@ -0,0 +1,133 @@ + + + + RUM Integ Test + + + + + + + + +

This application is used for RUM integ testing.

+
+ + + + + + +
+ + +
+ + + + + + + + + + + + + + + +
Request URL
Request Header
Request Body
+ + + + + + + + + + + + + +
Response Status Code
Response Header
Response Body
+ + diff --git a/app/page_event.html b/app/page_event.html new file mode 100644 index 00000000..a17e28a9 --- /dev/null +++ b/app/page_event.html @@ -0,0 +1,183 @@ + + + + RUM Integ Test + + + + + + + + +

This application is used for RUM integ testing.

+
+ + + + + + + + +
+ + + + + +
+ + + + + + + + + + + + + + + +
Request URL
Request Header
Request Body
+ + + + + + + + + + + + + +
Response Status Code
Response Header
Response Body
+ + diff --git a/app/post_load_command_queue_test.html b/app/post_load_command_queue_test.html new file mode 100644 index 00000000..2d4567ab --- /dev/null +++ b/app/post_load_command_queue_test.html @@ -0,0 +1,10 @@ + + + + RUM Integ Test + + + +

This application is used for RUM integ testing.

+ + diff --git a/app/pre_load_command_queue_test.html b/app/pre_load_command_queue_test.html new file mode 100644 index 00000000..1a943ebd --- /dev/null +++ b/app/pre_load_command_queue_test.html @@ -0,0 +1,10 @@ + + + + RUM Integ Test + + + +

This application is used for RUM integ testing.

+ + diff --git a/app/response.json b/app/response.json new file mode 100644 index 00000000..cf38f266 --- /dev/null +++ b/app/response.json @@ -0,0 +1,3 @@ +{ + "message": "Hello World!" +} diff --git a/app/web_vital_event.html b/app/web_vital_event.html new file mode 100644 index 00000000..e5e35fa0 --- /dev/null +++ b/app/web_vital_event.html @@ -0,0 +1,115 @@ + + + + RUM Integ Test + + + + + + + + + + +

This application is used for RUM integ testing.

+
+ + +
+ + +
+ + +
+ + + + + + + + + + + + + + + +
Request URL
Request Header
Request Body
+ + + + + + + + + + + + + +
Response Status Code
Response Header
Response Body
+ + diff --git a/jest.unit.config.js b/jest.unit.config.js new file mode 100644 index 00000000..72e09f25 --- /dev/null +++ b/jest.unit.config.js @@ -0,0 +1,24 @@ +module.exports = { + collectCoverage: !!process.env.BRAZIL_PACKAGE_NAME, + coveragePathIgnorePatterns: ['__tests__', '__integ__', '/node_modules/'], + globals: { + 'ts-jest': { + tsconfig: 'tsconfig.unit.json' + } + }, + testURL: + 'https://us-east-1.console.aws.amazon.com/console/home?region=us-east-1#feedback', + moduleFileExtensions: ['js', 'json', 'node', 'ts'], + testEnvironment: 'jest-environment-jsdom-global', + testMatch: ['**/__tests__/**/*.js', '**/__tests__/**/*.ts'], + transform: { '^.+\\.tsx?$': 'ts-jest' }, + reporters: ['default'], + coverageReporters: [ + 'json', + 'json-summary', + 'cobertura', + 'text', + 'html', + 'clover' + ] +}; diff --git a/nightwatch.conf.js b/nightwatch.conf.js new file mode 100644 index 00000000..5a962fcd --- /dev/null +++ b/nightwatch.conf.js @@ -0,0 +1,152 @@ +// Autogenerated by Nightwatch +// Refer to the online docs for more details: https://nightwatchjs.org/gettingstarted/configuration/ +const Services = {}; +loadServices(); + +module.exports = { + // An array of folders (excluding subfolders) where your tests are located; + // if this is not specified, the test source must be passed as the second argument to the test runner. + src_folders: [ + 'src/plugins/event-plugins/__nightwatch__/PageViewPlugin.test.js' + ], + + // See https://nightwatchjs.org/guide/working-with-page-objects/ + page_objects_path: '', + + // See https://nightwatchjs.org/guide/extending-nightwatch/#writing-custom-commands + custom_commands_path: '', + + // See https://nightwatchjs.org/guide/extending-nightwatch/#writing-custom-assertions + custom_assertions_path: '', + + // See https://nightwatchjs.org/guide/#external-globals + globals_path: '', + + webdriver: {}, + + test_settings: { + default: { + disable_error_log: false, + launch_url: 'https://nightwatchjs.org', + + screenshots: { + enabled: false, + path: 'screens', + on_failure: true + }, + + desiredCapabilities: { + browserName: 'chrome' + }, + + webdriver: { + start_process: true, + server_path: Services.chromedriver + ? Services.chromedriver.path + : '/usr/local/lib/node_modules/chromedriver/lib/chromedriver/chromedriver' + } + }, + + safari: { + desiredCapabilities: { + browserName: 'safari', + alwaysMatch: { + acceptInsecureCerts: false + } + }, + webdriver: { + port: 4445, + start_process: true, + server_path: '/usr/bin/safaridriver' + } + }, + + firefox: { + desiredCapabilities: { + browserName: 'firefox', + alwaysMatch: { + acceptInsecureCerts: true, + 'moz:firefoxOptions': { + args: [ + // '-headless', + // '-verbose' + ] + } + } + }, + webdriver: { + start_process: true, + port: 4444, + server_path: Services.geckodriver + ? Services.geckodriver.path + : '/usr/local/lib/node_modules/geckodriver/geckodriver', + cli_args: [ + // very verbose geckodriver logs + // '-vv' + ] + } + }, + + chrome: { + desiredCapabilities: { + browserName: 'chrome', + 'goog:chromeOptions': { + // More info on Chromedriver: https://sites.google.com/a/chromium.org/chromedriver/ + // + // This tells Chromedriver to run using the legacy JSONWire protocol (not required in Chrome 78) + w3c: false, + args: [ + //'--no-sandbox', + //'--ignore-certificate-errors', + //'--allow-insecure-localhost', + //'--headless' + ] + } + }, + + webdriver: { + start_process: true, + port: 9515, + server_path: Services.chromedriver + ? Services.chromedriver.path + : '/usr/local/lib/node_modules/chromedriver/lib/chromedriver/chromedriver', + cli_args: [ + // --verbose + ] + } + }, + + edge: { + desiredCapabilities: { + browserName: 'MicrosoftEdge', + 'ms:edgeOptions': { + w3c: false, + // More info on EdgeDriver: https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/capabilities-edge-options + args: [ + //'--headless' + ] + } + }, + + webdriver: { + start_process: true, + // Download msedgedriver from https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/ + // and set the location below: + server_path: '', + cli_args: [ + // --verbose + ] + } + } + } +}; + +function loadServices() { + try { + Services.chromedriver = require('chromedriver'); + } catch (err) {} + + try { + Services.geckodriver = require('geckodriver'); + } catch (err) {} +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..6f45a937 --- /dev/null +++ b/package.json @@ -0,0 +1,116 @@ +{ + "name": "aws-rum-web", + "version": "0.1.1", + "npm-pretty-much": { + "runRelease": "release", + "runTest": "never" + }, + "main": "dist/cjs/index.js", + "module": "dist/es/index.js", + "scripts": { + "build": "npm run build:schemas && webpack --config webpack/webpack.prod.js && npm run build:es && npm run build:cjs && npm run copy-cfg", + "build:es": "tsc --project ./tsconfig.es.json", + "build:cjs": "tsc --project ./tsconfig.cjs.json", + "build:dev": "npm run build:schemas && webpack --config webpack/webpack.dev.js", + "build:schemas": "scripts/generate-schema-ts", + "clean": "rm -rf ./build && rm -rf ./node_modules & rm package-lock.json", + "server": "webpack-dev-server --config webpack/webpack.dev.js", + "release": "npm run test && npm run build", + "lint": "node node_modules/tslint/bin/tslint --config ./tslint.json --project ./tsconfig.webpack.json --format verbose || exit 1", + "lint:fix": "node node_modules/tslint/bin/tslint -c ./tslint.json -p ./tsconfig.webpack.json --format verbose --fix", + "prettier": "npx prettier --check .", + "prettier:fix": "npx prettier --write .", + "test": "npm run build:dev && jest -c jest.unit.config.js", + "test:coverage": "jest -c jest.unit.config.js --coverage", + "integ": "npm run integ:chrome-headless", + "integ:chrome-headless": "npm run build:dev && cross-env NODE_OPTIONS=--max-http-header-size=80000 testcafe chrome:/apollo/env/DiamondToolkitBrowsersEnvironment/bin/chrome:headless --app \"http-server ./build/dev -s\" 'src/**/__integ__/**/*.(js|ts)'", + "integ:local": "npm run build:dev && cross-env NODE_OPTIONS=--max-http-header-size=80000 testcafe chrome --stage=local --app \"http-server ./build/dev -s\" 'src/**/__integ__/**/*.(js|ts)'", + "integ:local:chrome": "npm run build:dev && cross-env NODE_OPTIONS=--max-http-header-size=80000 testcafe chrome --stage=local --reporter spec:integ-test-results/chrome.testcafe.spec --app \"http-server ./build/dev -s\" 'src/**/__integ__/**/*.(js|ts)'", + "integ:local:firefox": "npm run build:dev && cross-env NODE_OPTIONS=--max-http-header-size=80000 testcafe firefox --stage=local --reporter spec:integ-test-results/firefox.testcafe.spec --app \"http-server ./build/dev -s\" 'src/**/__integ__/**/*.(js|ts)'", + "integ:local:safari": "npm run build:dev && cross-env NODE_OPTIONS=--max-http-header-size=80000 testcafe safari --stage=local --reporter spec:integ-test-results/safari.testcafe.spec --app \"http-server ./build/dev -s\" 'src/**/__integ__/**/*.(js|ts)'", + "integ:local:edge": "npm run build:dev && cross-env NODE_OPTIONS=--max-http-header-size=80000 testcafe edge --stage=local --reporter spec:integ-test-results/edge.testcafe.spec --app \"http-server ./build/dev -s\" 'src/**/__integ__/**/*.(js|ts)'", + "integ:local:ie": "npm run build:dev && cross-env NODE_OPTIONS=--max-http-header-size=80000 testcafe ie --stage=local --reporter spec:integ-test-results/ie.testcafe.spec --app \"http-server ./build/dev -s\" 'src/**/__integ__/**/*.(js|ts)'", + "preinteg:local:nightwatch": "http-server ./build/dev -s &", + "integ:local:nightwatch": "nightwatch", + "postinteg:local:nightwatch": "kill $(lsof -t -i:8080)", + "preinteg:local:nightwatch:chrome": "http-server ./build/dev -s &", + "integ:local:nightwatch:chrome": "nightwatch -e chrome", + "postinteg:local:nightwatch:chrome": "kill $(lsof -t -i:8080)", + "preinteg:local:nightwatch:firefox": "http-server ./build/dev -s &", + "integ:local:nightwatch:firefox": "nightwatch -e firefox", + "postinteg:local:nightwatch:firefox": "kill $(lsof -t -i:8080)" + }, + "author": "Amazon CloudWatch RUM Staff ", + "devDependencies": { + "@babel/core": "~7.6.3", + "@babel/polyfill": "~7.6.0", + "@babel/preset-env": "~7.6.3", + "@types/jest": "^26.0.20", + "@types/ua-parser-js": "^0.7.35", + "@types/uuid": "^8.3.0", + "@webpack-cli/serve": "^1.5.2", + "awesome-typescript-loader": "^5.2.1", + "babel-loader": "~8.0.6", + "case-sensitive-paths-webpack-plugin": "^2.1.2", + "copy-webpack-plugin": "^6.3.2", + "copyfiles": "^2.4.1", + "cross-env": "^7.0.3", + "http-server": "^0.12.3", + "jest": "^27.2.2", + "jest-date-mock": "^1.0.8", + "jest-environment-jsdom": "^27.2.2", + "jest-environment-jsdom-global": "^3.0.0", + "jest-mock-random": "^1.1.1", + "jsdom": "^16.4.0", + "json-schema-to-typescript": "^10.1.3", + "lodash": "^4.17.20", + "nightwatch": "^1.7.8", + "node-fetch": "^2.6.1", + "pre-commit": "^1.2.2", + "prettier": "2.2.1", + "testcafe": "^1.11.0", + "testcafe-reporter-html": "^1.4.6", + "testcafe-reporter-json": "^1.0.0", + "ts-jest": "^27.0.5", + "ts-loader": "^8.0.14", + "tslint": "^5.11.0", + "tslint-config-prettier": "^1.18.0", + "typescript": "^4.4.3", + "web-streams-polyfill": "^3.1.0", + "webpack": "^5.54.0", + "webpack-cli": "^3.3.12", + "webpack-dev-middleware": "^3.7.3", + "webpack-dev-server": "^4.3.0", + "webpack-license-plugin": "^4.2.0", + "webpack-merge": "^4.2.2", + "xhr-mock": "^2.5.1" + }, + "dependencies": { + "@aws-crypto/sha256-js": "^1.1.0", + "@aws-sdk/fetch-http-handler": "^3.6.1", + "@aws-sdk/protocol-http": "^3.6.1", + "@aws-sdk/signature-v4": "^3.6.1", + "@aws-sdk/util-hex-encoding": "^3.6.1", + "shimmer": "^1.2.1", + "ua-parser-js": "^0.7.23", + "uuid": "^8.3.2", + "web-vitals": "^1.1.1" + }, + "pre-commit": [ + "lint", + "prettier" + ], + "jest": { + "setupFiles": [ + "/tst/jest.setup.ts", + "jest-date-mock" + ], + "transform": { + ".ts": "/node_modules/ts-jest/preprocessor.js" + }, + "moduleFileExtensions": [ + "ts", + "js" + ] + } +} diff --git a/scripts/generate-schema-ts b/scripts/generate-schema-ts new file mode 100755 index 00000000..d01cb299 --- /dev/null +++ b/scripts/generate-schema-ts @@ -0,0 +1,13 @@ +#!/bin/bash + +lib="src/event-schemas/*.json" +regex="(.*)\.json" + +for schema in $lib +do + file=$(basename $schema) + if [[ $file =~ $regex ]] + then + npx json-schema-to-typescript --input "$schema" --output "src/events/${BASH_REMATCH[1]}.ts" + fi +done diff --git a/src/CommandQueue.ts b/src/CommandQueue.ts new file mode 100644 index 00000000..e24315bc --- /dev/null +++ b/src/CommandQueue.ts @@ -0,0 +1,117 @@ +import { CredentialProvider, Credentials } from '@aws-sdk/types'; +import { PartialConfig, Orchestration } from './orchestration/Orchestration'; + +/** + * An AWS RUM Client command. + * + * A command is one of the following: + * - <'setAwsCredentials', AWS.Credentials> + * - <'addPlugin', TelemetryPlugin> + * - <'configurePlugin', object> + */ +export type Command = { c: string; p: any }; + +/** + * The global configuration object is defined in the loader script, so we cannot trust its types. + */ +export type AwsRumClientInit = { + q: []; + n: string; + i: string; + a: string; + r: string; + v: string; + c?: PartialConfig; +}; + +/** + * A utility for collecting telemetry from JavaScript applications. + * + * For example: + * - Pages visited (user workflow) + * - Page load time + * - DOM events + */ +export class CommandQueue { + private orchestration: Orchestration; + + private commandHandlerMap = { + setAwsCredentials: ( + payload: Credentials | CredentialProvider + ): void => { + this.orchestration.setAwsCredentials(payload); + }, + configurePlugin: (payload: any): void => { + if (payload.pluginId && payload.config) { + this.orchestration.configurePlugin( + payload.pluginId, + payload.config + ); + } else { + throw new Error('IncorrectParametersException'); + } + }, + recordPageView: (payload: string): void => { + this.orchestration.recordPageView(payload); + }, + recordError: (payload: any): void => { + this.orchestration.recordError(payload); + }, + dispatch: (): void => { + this.orchestration.dispatch(); + }, + dispatchBeacon: (): void => { + this.orchestration.dispatchBeacon(); + }, + enable: (): void => { + this.orchestration.enable(); + }, + disable: (): void => { + this.orchestration.disable(); + }, + allowCookies: (allow: boolean): void => { + if (typeof allow === 'boolean') { + this.orchestration.allowCookies(allow); + } else { + throw new Error('IncorrectParametersException'); + } + } + }; + + constructor(awsRum: AwsRumClientInit) { + this.orchestration = new Orchestration( + awsRum.i, + awsRum.a, + awsRum.v, + awsRum.r, + awsRum.c + ); + + // Overwrite the global API to use CommandQueue + // @ts-ignore + window[awsRum.n] = (c: string, p: any) => { + this.push({ c, p }); + }; + + // Execute any queued commands + awsRum.q.forEach((command: Command) => { + this.push(command); + }); + + // Release the original queue + awsRum.q = []; + } + + /** + * Add a command to the command queue. + */ + async push(command: Command) { + // @ts-ignore + const commandHandler = await this.commandHandlerMap[command.c]; + if (commandHandler) { + commandHandler(command.p); + } else { + throw new Error(`UnsupportedOperationException: ${command.c}`); + } + } +} diff --git a/src/__integ__/CommandQueue.test.ts b/src/__integ__/CommandQueue.test.ts new file mode 100644 index 00000000..87012c2c --- /dev/null +++ b/src/__integ__/CommandQueue.test.ts @@ -0,0 +1,41 @@ +fixture('Command Queue'); + +// @ts-ignore +test.clientScripts({ + content: ` + window.addEventListener('unhandledrejection', function (e) { + console.error(e.reason.message); + });` +})( + 'command enqueued before RUM web client loads is executed after RUM web client loads', + async (t: TestController) => { + await t.navigateTo( + 'http://localhost:8080/pre_load_command_queue_test.html' + ); + await t.wait(2000); + const error = (await t.getBrowserConsoleMessages()).error; + await t + .expect(error[0]) + .contains('UnsupportedOperationException: unsupported_command'); + } +); + +// @ts-ignore +test.clientScripts({ + content: ` + window.addEventListener('unhandledrejection', function (e) { + console.error(e.reason.message); + });` +})( + 'command enqueued after RUM web client loads is executed', + async (t: TestController) => { + await t.navigateTo( + 'http://localhost:8080/post_load_command_queue_test.html' + ); + await t.wait(2000); + const error = (await t.getBrowserConsoleMessages()).error; + await t + .expect(error[0]) + .contains('UnsupportedOperationException: unsupported_command'); + } +); diff --git a/src/__integ__/cookiesDisabled.test.ts b/src/__integ__/cookiesDisabled.test.ts new file mode 100644 index 00000000..792324da --- /dev/null +++ b/src/__integ__/cookiesDisabled.test.ts @@ -0,0 +1,66 @@ +import { SESSION_START_EVENT_TYPE } from '../sessions/SessionManager'; +import { Selector } from 'testcafe'; +import { REQUEST_BODY } from '../test-utils/integ-test-utils'; + +const dispatch: Selector = Selector(`#dispatch`); +const clear: Selector = Selector(`#clearRequestResponse`); + +fixture('Cookies Disabled').page('http://localhost:8080/cookies_disabled.html'); + +test('when page is re-loaded with cookies disabled, session start is dispatched', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t + .wait(300) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const jsonOne = JSON.parse(await REQUEST_BODY.textContent); + const eventTypeOne = jsonOne.batch.events[0].type; + const userIdOne = jsonOne.batch.user.userId; + const sessionIdOne = jsonOne.batch.user.sessionId; + + await t.click(clear).eval(() => location.reload()); + + await t + .wait(300) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const jsonTwo = JSON.parse(await REQUEST_BODY.textContent); + const eventTypeTwo = jsonTwo.batch.events[0].type; + const userIdTwo = jsonTwo.batch.user.userId; + const sessionIdTwo = jsonTwo.batch.user.sessionId; + + await t + .expect(eventTypeOne) + .eql(SESSION_START_EVENT_TYPE) + .expect(eventTypeTwo) + .eql(SESSION_START_EVENT_TYPE) + .expect(userIdOne) + .notEql(userIdTwo) + .expect(sessionIdTwo) + .notEql(sessionIdOne); +}); + +test('when page is loaded with cookies disabled, session start includes meta data', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t + .wait(300) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const jsonOne = JSON.parse(await REQUEST_BODY.textContent); + const eventTypeOne = jsonOne.batch.events[0].type; + const metaDataOne = JSON.parse(jsonOne.batch.events[0].metadata); + + await t + .expect(eventTypeOne) + .eql(SESSION_START_EVENT_TYPE) + .expect(metaDataOne.url) + .eql('http://localhost:8080/cookies_disabled.html'); +}); diff --git a/src/__integ__/cookiesEnabled.test.ts b/src/__integ__/cookiesEnabled.test.ts new file mode 100644 index 00000000..ed351e7b --- /dev/null +++ b/src/__integ__/cookiesEnabled.test.ts @@ -0,0 +1,55 @@ +import { SESSION_START_EVENT_TYPE } from '../sessions/SessionManager'; +import { Selector } from 'testcafe'; +import { REQUEST_BODY } from '../test-utils/integ-test-utils'; + +const dispatch: Selector = Selector(`#dispatch`); +const clear: Selector = Selector(`#clearRequestResponse`); + +fixture('Cookies Enabled').page('http://localhost:8080/cookies_enabled.html'); + +test('when page is re-loaded with cookies enabled, session start is not dispatched', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t + .wait(300) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const jsonOne = JSON.parse(await REQUEST_BODY.textContent); + const eventTypeOne = jsonOne.batch.events[0].type; + + await t + .expect(eventTypeOne) + .eql(SESSION_START_EVENT_TYPE) + .click(clear) + .eval(() => location.reload()); + + await t + .wait(300) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch') + .expect(REQUEST_BODY.textContent) + .notContains(SESSION_START_EVENT_TYPE); +}); + +test('when page is loaded with cookies enabled, session start includes meta data', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t + .wait(300) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const jsonOne = JSON.parse(await REQUEST_BODY.textContent); + const eventTypeOne = jsonOne.batch.events[0].type; + const metaDataOne = JSON.parse(jsonOne.batch.events[0].metadata); + + await t + .expect(eventTypeOne) + .eql(SESSION_START_EVENT_TYPE) + .expect(metaDataOne.url) + .eql('http://localhost:8080/cookies_enabled.html'); +}); diff --git a/src/__integ__/indexPage.test.ts b/src/__integ__/indexPage.test.ts new file mode 100644 index 00000000..a2a92a34 --- /dev/null +++ b/src/__integ__/indexPage.test.ts @@ -0,0 +1,10 @@ +import { Selector } from 'testcafe'; + +fixture('Sanity check').page('http://localhost:8080/'); + +test('index.html of the integ test application loads.', async (t: TestController) => { + const welcome: Selector = Selector('#welcome'); + await t + .expect(welcome.textContent) + .eql('This application is used for RUM integ testing.'); +}); diff --git a/src/__tests__/CommandQueue.test.ts b/src/__tests__/CommandQueue.test.ts new file mode 100644 index 00000000..9a964743 --- /dev/null +++ b/src/__tests__/CommandQueue.test.ts @@ -0,0 +1,177 @@ +import { CommandQueue } from '../CommandQueue'; +import { Orchestration } from '../orchestration/Orchestration'; + +const getCommandQueue = () => { + return new CommandQueue({ + q: [], + n: 'cwr', + i: 'application_id', + a: 'application_name', + v: '1.0', + r: 'us-west-2' + }); +}; + +const disable = jest.fn(); +const enable = jest.fn(); +const dispatch = jest.fn(); +const dispatchBeacon = jest.fn(); +const setAwsCredentials = jest.fn(); +const configurePlugin = jest.fn(); +const allowCookies = jest.fn(); +const recordPageView = jest.fn(); +const recordError = jest.fn(); +jest.mock('../orchestration/Orchestration', () => ({ + Orchestration: jest.fn().mockImplementation(() => ({ + disable, + enable, + dispatch, + dispatchBeacon, + setAwsCredentials, + configurePlugin, + allowCookies, + recordPageView, + recordError + })) +})); + +describe('CommandQueue tests', () => { + beforeEach(() => { + window.performance.getEntriesByType = jest.fn(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('disable calls Orchestration.disable', async () => { + const cq: CommandQueue = getCommandQueue(); + const result = await cq.push({ + c: 'disable', + p: undefined + }); + expect(Orchestration).toHaveBeenCalled(); + expect(disable).toHaveBeenCalled(); + }); + + test('push() recordEvent throws UnsupportedOperationException', async () => { + const commandQueue: CommandQueue = getCommandQueue(); + commandQueue + .push({ + c: 'recordEvent', + p: { event: 'my_event' } + }) + .then(() => fail()) + .catch((e) => + expect(e).toMatch('UnsupportedOperationException: recordEvent') + ); + }); + + test('enable calls Orchestration.enable', async () => { + const cq: CommandQueue = getCommandQueue(); + const result = await cq.push({ + c: 'enable', + p: undefined + }); + expect(Orchestration).toHaveBeenCalled(); + expect(enable).toHaveBeenCalled(); + }); + + test('dispatch calls Orchestration.dispatch', async () => { + const cq: CommandQueue = getCommandQueue(); + const result = await cq.push({ + c: 'dispatch', + p: undefined + }); + expect(Orchestration).toHaveBeenCalled(); + expect(dispatch).toHaveBeenCalled(); + }); + + test('dispatchBeacon calls Orchestration.dispatchBeacon', async () => { + const cq: CommandQueue = getCommandQueue(); + const result = await cq.push({ + c: 'dispatchBeacon', + p: undefined + }); + expect(Orchestration).toHaveBeenCalled(); + expect(dispatchBeacon).toHaveBeenCalled(); + }); + + test('setAwsCredentials calls Orchestration.setAwsCredentials', async () => { + const cq: CommandQueue = getCommandQueue(); + const result = await cq.push({ + c: 'setAwsCredentials', + p: { event: 'my_event' } + }); + expect(Orchestration).toHaveBeenCalled(); + expect(setAwsCredentials).toHaveBeenCalled(); + }); + + test('configurePlugin calls Orchestration.configurePlugin', async () => { + const cq: CommandQueue = getCommandQueue(); + const result = await cq.push({ + c: 'configurePlugin', + p: { pluginId: 'myplugin', config: {} } + }); + expect(Orchestration).toHaveBeenCalled(); + expect(configurePlugin).toHaveBeenCalled(); + }); + + test('allowCookies calls Orchestration.allowCookies', async () => { + const cq: CommandQueue = getCommandQueue(); + await cq.push({ + c: 'allowCookies', + p: false + }); + expect(Orchestration).toHaveBeenCalled(); + expect(allowCookies).toHaveBeenCalled(); + }); + + test('recordPageView calls Orchestration.recordPageView', async () => { + const cq: CommandQueue = getCommandQueue(); + await cq.push({ + c: 'recordPageView', + p: false + }); + expect(Orchestration).toHaveBeenCalled(); + expect(recordPageView).toHaveBeenCalled(); + }); + + test('recordError calls Orchestration.recordError', async () => { + const cq: CommandQueue = getCommandQueue(); + await cq.push({ + c: 'recordError', + p: false + }); + expect(Orchestration).toHaveBeenCalled(); + expect(recordError).toHaveBeenCalled(); + }); + + test('allowCookies fails when paylod is non-boolean', async () => { + const cq: CommandQueue = getCommandQueue(); + await cq + .push({ + c: 'allowCookies', + p: '' + }) + .then((v) => fail('command should fail')) + .catch((e) => + expect(e.message).toEqual('IncorrectParametersException') + ); + }); + + test('when function is unknown, UnsupportedOperationException is thrown', async () => { + const cq: CommandQueue = getCommandQueue(); + await cq + .push({ + c: 'badCommand', + p: undefined + }) + .then((v) => fail('command should fail')) + .catch((e) => + expect(e.message).toEqual( + 'UnsupportedOperationException: badCommand' + ) + ); + }); +}); diff --git a/src/dispatch/Authentication.ts b/src/dispatch/Authentication.ts new file mode 100644 index 00000000..66047bdd --- /dev/null +++ b/src/dispatch/Authentication.ts @@ -0,0 +1,129 @@ +import { CRED_COOKIE_NAME } from '../utils/constants'; +import { CognitoIdentityClient } from './CognitoIdentityClient'; +import { Config } from '../orchestration/Orchestration'; +import { Credentials } from '@aws-sdk/types'; +import { FetchHttpHandler } from '@aws-sdk/fetch-http-handler'; +import { StsClient } from './StsClient'; +import { storeCookie, getCookie } from '../utils/cookies-utils'; + +export class Authentication { + private cognitoIdentityClient: CognitoIdentityClient; + private stsClient: StsClient; + private config: Config; + + constructor(config: Config) { + const region: string = config.identityPoolId.split(':')[0]; + this.config = config; + this.stsClient = new StsClient({ + fetchRequestHandler: new FetchHttpHandler(), + region + }); + this.cognitoIdentityClient = new CognitoIdentityClient({ + fetchRequestHandler: new FetchHttpHandler(), + region + }); + } + + /** + * Provides credentials for an anonymous (guest) user. These credentials are retrieved from the first successful + * provider in a chain. + * + * Credentials are stored in and retrieved from a non-HttpOnly cookie. This prevents the client from having to + * re-authenticate every time the client loads, which (1) improves the performance of the RUM web client and (2) + * reduces the load on AWS services Cognito and STS. + * + * While storing credentials in a non-HttpOnly cookie puts the cookie at greater risk of being leaked through an + * XSS attack, there is no impact if the credentials were to be leaked. This is because (1) the identity pool ID + * and role ARN are public and (2) the credentials are for an anonymous (guest) user. + * + * Regarding (1), the identity pool ID and role ARN are, by necessity, public. These identifiers are shipped with + * each application as part of Cognito's Basic (Classic) authentication flow. The identity pool ID and role ARN + * are not secret. + * + * Regarding (2), the authentication chain implemented in this file only supports anonymous (guest) + * authentication. When the Cognito authentication flow is executed, {@code AnonymousCognitoCredentialsProvider} + * does not communicate with a login provider such as Amazon, Facebook or Google. Instead, it relies on (a) the + * identity pool supporting unauthenticated identities and (b) the IAM role policy enabling login through the + * identity pool. If the identity pool does not support unauthenticated identities, this authentication chain + * will not succeed. + * + * Taken together, (1) and (2) mean that if these temporary credentials were to be leaked, the leaked credentials + * would not allow a bad actor to gain access to anything which they did not already have public access to. + * + * Implements CredentialsProvider = Provider + */ + public ChainAnonymousCredentialsProvider = async (): Promise => { + return this.AnonymousCookieCredentialsProvider().catch( + this.AnonymousCognitoCredentialsProvider + ); + }; + + /** + * Provides credentials for an anonymous (guest) user. These credentials are read from a cookie. + * + * Implements CredentialsProvider = Provider + */ + private AnonymousCookieCredentialsProvider = async (): Promise => { + return new Promise((resolve, reject) => { + const credString = getCookie(CRED_COOKIE_NAME); + if (credString && this.useCookies() && atob) { + let credentials; + try { + credentials = JSON.parse(atob(credString)); + } catch (e) { + // Error decoding or parsing the cookie -- abort + reject(); + } + // The expiration property of Credentials has a date type. Because the date was serialized as a string, + // we need to convert it back into a date, otherwise the AWS SDK signing middleware + // (@aws-sdk/middleware-signing) will throw an exception and no credentials will be returned. + credentials.expiration = new Date(credentials.expiration); + resolve(credentials); + } else { + reject(); + } + }); + }; + + /** + * Provides credentials for an anonymous (guest) user. These credentials are retrieved from Cognito's basic + * (classic) authflow. + * + * See https://docs.aws.amazon.com/cognito/latest/developerguide/authentication-flow.html + * + * Implements CredentialsProvider = Provider + */ + private AnonymousCognitoCredentialsProvider = async (): Promise => { + return this.cognitoIdentityClient + .getId({ + IdentityPoolId: this.config.identityPoolId as string + }) + .then((getIdResponse) => + this.cognitoIdentityClient.getOpenIdToken(getIdResponse) + ) + .then((getOpenIdTokenResponse) => + this.stsClient.assumeRoleWithWebIdentity({ + RoleArn: this.config.guestRoleArn as string, + RoleSessionName: 'cwr', + WebIdentityToken: getOpenIdTokenResponse.Token + }) + ) + .then((credentials) => { + if (btoa) { + storeCookie( + CRED_COOKIE_NAME, + btoa(JSON.stringify(credentials)), + undefined, + undefined, + credentials.expiration + ); + } + + return credentials; + }); + }; + + private useCookies() { + return navigator.cookieEnabled && this.config.allowCookies; + } +} diff --git a/src/dispatch/BeaconHttpHandler.ts b/src/dispatch/BeaconHttpHandler.ts new file mode 100644 index 00000000..bc0129ab --- /dev/null +++ b/src/dispatch/BeaconHttpHandler.ts @@ -0,0 +1,34 @@ +import { HttpHandler, HttpRequest, HttpResponse } from '@aws-sdk/protocol-http'; +import { buildQueryString } from '@aws-sdk/querystring-builder'; + +export class BeaconHttpHandler implements HttpHandler { + handle(request: HttpRequest): Promise<{ response: HttpResponse }> { + const queued = this.sendBeacon(request); + return new Promise((resolve, reject) => { + if (queued) { + resolve({ + response: new HttpResponse({ statusCode: 200 }) + }); + } else { + reject(); + } + }); + } + + private sendBeacon(signedRequest: HttpRequest) { + let path = signedRequest.path; + if (signedRequest.query) { + const queryString = buildQueryString(signedRequest.query); + if (queryString) { + path += `?${queryString}`; + } + } + + const { port } = signedRequest; + const url = `${signedRequest.protocol}//${signedRequest.hostname}${ + port ? `:${port}` : '' + }${path}`; + + return navigator.sendBeacon(url, signedRequest.body); + } +} diff --git a/src/dispatch/CognitoIdentityClient.ts b/src/dispatch/CognitoIdentityClient.ts new file mode 100644 index 00000000..28afd0df --- /dev/null +++ b/src/dispatch/CognitoIdentityClient.ts @@ -0,0 +1,142 @@ +import { HttpHandler, HttpRequest } from '@aws-sdk/protocol-http'; +import { Credentials } from '@aws-sdk/types'; + +const METHOD: string = 'POST'; +const CONTENT_TYPE: string = 'application/x-amz-json-1.1'; +const PROTOCOL: string = 'https:'; + +// Targets +const GET_ID_TARGET: string = 'AWSCognitoIdentityService.GetId'; +const GET_TOKEN_TARGET: string = 'AWSCognitoIdentityService.GetOpenIdToken'; +const GET_CREDENTIALS_TARGET: string = + 'AWSCognitoIdentityService.GetCredentialsForIdentity'; + +interface CognitoProviderParameters { + /** + * The unique identifier for the identity pool from which an identity should + * be retrieved or generated. + */ + identityPoolId: string; + /** + * The SDK client with which the credential provider will contact the Amazon + * Cognito service. + */ + client: CognitoIdentityClient; +} + +export const fromCognitoIdentityPool = ( + params: CognitoProviderParameters +): (() => Promise) => { + return () => params.client.getCredentialsForIdentity(params.identityPoolId); +}; + +export declare type CognitoIdentityClientConfig = { + fetchRequestHandler: HttpHandler; + region?: string; +}; + +export class CognitoIdentityClient { + private fetchRequestHandler: HttpHandler; + private hostname: string; + + constructor(config: CognitoIdentityClientConfig) { + this.hostname = `cognito-identity.${config.region}.amazonaws.com`; + this.fetchRequestHandler = config.fetchRequestHandler; + } + + public getId = async (request: { IdentityPoolId: string }) => { + const requestPayload = JSON.stringify(request); + + const idRequest = this.getHttpRequest(GET_ID_TARGET, requestPayload); + return this.fetchRequestHandler + .handle(idRequest) + .then(({ response }) => + response.body + .getReader() + .read() + .then(({ value }) => + JSON.parse(String.fromCharCode.apply(null, value)) + ) + ) + .catch(() => { + throw new Error('CWR: Failed to retrieve Cognito identity'); + }); + }; + + public getOpenIdToken = async (request: { IdentityId: string }) => { + const requestPayload = JSON.stringify(request); + const tokenRequest = this.getHttpRequest( + GET_TOKEN_TARGET, + requestPayload + ); + + return this.fetchRequestHandler + .handle(tokenRequest) + .then(({ response }) => + response.body + .getReader() + .read() + .then(({ value }) => + JSON.parse(String.fromCharCode.apply(null, value)) + ) + ) + .catch(() => { + throw new Error('CWR: Failed to retrieve Cognito OpenId token'); + }); + }; + + public getCredentialsForIdentity = async ( + identityId: string + ): Promise => { + const requestPayload = JSON.stringify({ IdentityId: identityId }); + const credentialRequest = this.getHttpRequest( + GET_CREDENTIALS_TARGET, + requestPayload + ); + + return this.fetchRequestHandler + .handle(credentialRequest) + .then(({ response }) => { + return response.body + .getReader() + .read() + .then(({ value }) => { + const { IdentityId, Credentials } = JSON.parse( + String.fromCharCode.apply(null, value) + ); + + const { + AccessKeyId, + Expiration, + SecretAccessKey, + SessionToken + } = Credentials; + + return { + identityId: IdentityId as string, + accessKeyId: AccessKeyId as string, + secretAccessKey: SecretAccessKey as string, + sessionToken: SessionToken as string, + expiration: new Date(Expiration * 1000) + }; + }); + }) + .catch(() => { + throw new Error( + 'CWR: Failed to retrieve credentials for Cognito identity' + ); + }); + }; + + private getHttpRequest = (target: string, payload: string) => + new HttpRequest({ + method: METHOD, + headers: { + 'content-type': CONTENT_TYPE, + 'x-amz-target': target + }, + protocol: PROTOCOL, + hostname: this.hostname, + body: payload + }); +} diff --git a/src/dispatch/DataPlaneClient.ts b/src/dispatch/DataPlaneClient.ts new file mode 100644 index 00000000..8c37fdf5 --- /dev/null +++ b/src/dispatch/DataPlaneClient.ts @@ -0,0 +1,161 @@ +import { toHex } from '@aws-sdk/util-hex-encoding'; +import { SignatureV4 } from '@aws-sdk/signature-v4'; +import { + CredentialProvider, + Credentials, + HttpResponse, + RequestPresigningArguments +} from '@aws-sdk/types'; +import { Sha256 } from '@aws-crypto/sha256-js'; +import { HttpHandler, HttpRequest } from '@aws-sdk/protocol-http'; +import { getHost, getScheme } from '../utils/common-utils'; +import { + ApplicationDetails, + LogEventsRequest, + UserDetails, + Event +} from './dataplane'; + +const SERVICE: string = 'rum'; +const METHOD: string = 'POST'; +const CONTENT_TYPE_JSON: string = 'application/json'; +const CONTENT_TYPE_TEXT: string = 'text/plain;charset=UTF-8'; + +const REQUEST_PRESIGN_ARGS: RequestPresigningArguments = { expiresIn: 60 }; + +declare type SerializedEvent = { + id: string | undefined; + timestamp: Date | number | undefined; + type: string | undefined; + metadata?: string; + details: string | undefined; +}; + +declare type SerializedRequest = { + batch: { + batchId: string; + application: ApplicationDetails; + user: UserDetails; + events: SerializedEvent[]; + }; +}; + +export declare type DataPlaneClientConfig = { + fetchRequestHandler: HttpHandler; + beaconRequestHandler: HttpHandler; + endpoint: string; + region: string; + credentials: CredentialProvider | Credentials; +}; + +export class DataPlaneClient { + private config: DataPlaneClientConfig; + private awsSigV4: SignatureV4; + + constructor(config: DataPlaneClientConfig) { + this.config = config; + this.awsSigV4 = new SignatureV4({ + applyChecksum: true, + credentials: config.credentials, + region: config.region, + service: SERVICE, + uriEscapePath: true, + sha256: Sha256 + }); + } + + public sendFetch = async ( + logEventsRequest: LogEventsRequest + ): Promise<{ response: HttpResponse }> => { + const host = getHost(this.config.endpoint); + const serializedRequest: string = JSON.stringify( + serializeRequest(logEventsRequest) + ); + const request = new HttpRequest({ + method: METHOD, + headers: { + 'content-type': CONTENT_TYPE_JSON, + 'X-Amz-Content-Sha256': await hashAndEncode(serializedRequest), + host + }, + protocol: getScheme(this.config.endpoint), + hostname: host, + path: `/application/${logEventsRequest.applicationId}/events`, + body: serializedRequest + }); + + // @ts-ignore + const signedRequest: HttpRequest = await this.awsSigV4.sign(request); + const httpResponse: Promise<{ + response: HttpResponse; + }> = this.config.fetchRequestHandler.handle(signedRequest); + return httpResponse; + }; + + public sendBeacon = async ( + logEventsRequest: LogEventsRequest + ): Promise<{ response: HttpResponse }> => { + const host = getHost(this.config.endpoint); + const serializedRequest: string = JSON.stringify( + serializeRequest(logEventsRequest) + ); + const request = new HttpRequest({ + method: METHOD, + headers: { + 'content-type': CONTENT_TYPE_TEXT, + 'X-Amz-Content-Sha256': await hashAndEncode(serializedRequest), + host + }, + protocol: getScheme(this.config.endpoint), + hostname: host, + path: `/application/${logEventsRequest.applicationId}/events`, + body: serializedRequest + }); + + // @ts-ignore + const preSignedRequest: HttpRequest = await this.awsSigV4.presign( + request, + REQUEST_PRESIGN_ARGS + ); + const httpResponse: Promise<{ + response: HttpResponse; + }> = this.config.beaconRequestHandler.handle(preSignedRequest); + return httpResponse; + }; +} + +const serializeRequest = (request: LogEventsRequest): SerializedRequest => { + // If we were using the AWS SDK client here then the serialization would be handled for us through a generated + // serialization/deserialization library. However, since much of the generated code is unnecessary, we do the + // serialization ourselves with this function. + const serializedEvents: SerializedEvent[] = []; + request.batch.events.forEach((e) => + serializedEvents.push(serializeEvent(e)) + ); + const serializedRequest: SerializedRequest = { + batch: { + batchId: request.batch.batchId, + application: request.batch.application, + user: request.batch.user, + events: serializedEvents + } + }; + return serializedRequest; +}; + +const serializeEvent = (event: Event): SerializedEvent => { + return { + id: event.id, + // Dates must be converted to timestamps before serialization. + timestamp: Math.round(event.timestamp.getTime() / 1000), + type: event.type, + metadata: event.metadata, + details: event.details + }; +}; + +const hashAndEncode = async (payload: string) => { + const sha256 = new Sha256(); + sha256.update(payload); + return toHex(await sha256.digest()).toLowerCase(); +}; diff --git a/src/dispatch/Dispatch.ts b/src/dispatch/Dispatch.ts new file mode 100644 index 00000000..6b5e6c07 --- /dev/null +++ b/src/dispatch/Dispatch.ts @@ -0,0 +1,170 @@ +import { CredentialProvider, Credentials, HttpResponse } from '@aws-sdk/types'; +import { EventCache } from '../event-cache/EventCache'; +import { DataPlaneClient } from './DataPlaneClient'; +import { BeaconHttpHandler } from './BeaconHttpHandler'; +import { FetchHttpHandler } from './FetchHttpHandler'; +import { LogEventsRequest } from './dataplane'; +import { Config } from '../orchestration/Orchestration'; + +type SendFunction = ( + logEventsRequest: LogEventsRequest +) => Promise<{ response: HttpResponse }>; + +export type ClientBuilder = ( + endpoint: string, + region: string, + credentials: CredentialProvider | Credentials +) => DataPlaneClient; + +export class Dispatch { + private applicationId: string; + private region: string; + private endpoint: string; + private eventCache: EventCache; + private rum: DataPlaneClient | undefined; + private enabled: boolean; + private dispatchTimerId: number | undefined; + private buildClient: ClientBuilder; + private config: Config; + + constructor( + applicationId: string, + region: string, + endpoint: string, + eventCache: EventCache, + config: Config + ) { + this.applicationId = applicationId; + this.region = region; + this.endpoint = endpoint; + this.eventCache = eventCache; + this.enabled = true; + this.buildClient = config.clientBuilder || this.defaultClientBuilder; + this.config = config; + this.startDispatchTimer(); + } + + /** + * Dispatch will send requests to data plane. + */ + public enable(): void { + this.enabled = true; + this.startDispatchTimer(); + } + + /** + * Dispatch will not send requests to data plane. + */ + public disable(): void { + this.stopDispatchTimer(); + this.enabled = false; + } + + /** + * Set the authentication token that will be used to authenticate with the + * data plane service (AWS auth). + * @param credentials A set of AWS credentials from the application's authflow. + */ + public setAwsCredentials( + credentialProvider: Credentials | CredentialProvider + ): void { + this.rum = this.buildClient( + this.endpoint, + this.region, + credentialProvider + ); + if (typeof credentialProvider === 'function') { + // In case a beacon in the first dispatch, we must pre-fetch credentials into a cookie so there is no delay + // to fetch credentials while the page is closing. + (credentialProvider as () => Promise)(); + } + } + + /** + * Send meta data and events to the AWS RUM data plane service via fetch. + */ + public dispatchFetch = async (): Promise<{ response: HttpResponse }> => { + return this.dispatch(this.rum.sendFetch); + }; + + /** + * Send meta data and events to the AWS RUM data plane service via beacon. + */ + public dispatchBeacon = async (): Promise<{ response: HttpResponse }> => { + return this.dispatch(this.rum.sendBeacon); + }; + + /** + * Automatically dispatch cached events. + */ + public startDispatchTimer() { + document.addEventListener('visibilitychange', this.dispatchBeacon); + document.addEventListener('pagehide', this.dispatchBeacon); + if (this.config.dispatchInterval <= 0 || this.dispatchTimerId) { + return; + } + this.dispatchTimerId = window.setInterval( + this.dispatchFetch, + this.config.dispatchInterval + ); + } + + /** + * Stop automatically dispatching cached events. + */ + public stopDispatchTimer() { + document.removeEventListener('visibilitychange', this.dispatchBeacon); + document.removeEventListener('pagehide', this.dispatchBeacon); + if (this.dispatchTimerId) { + window.clearInterval(this.dispatchTimerId); + this.dispatchTimerId = undefined; + } + } + + private async dispatch( + send: SendFunction + ): Promise<{ response: HttpResponse }> { + if (!this.enabled) { + return; + } + + if (!this.rum) { + throw new Error( + 'Cannot dispatch events: no valid AWS credentials.' + ); + } + + if (!this.eventCache.hasEvents()) { + return; + } + + const logEventsRequest: LogEventsRequest = { + applicationId: this.applicationId, + batch: this.eventCache.getEventBatch() + }; + + return send(logEventsRequest); + } + + /** + * The default method for creating data plane service clients. + * @param endpoint Service endpoint. + * @param region Service region. + * @param credentials AWS credentials. + */ + private defaultClientBuilder: ClientBuilder = ( + endpoint, + region, + credentials + ) => { + return new DataPlaneClient({ + fetchRequestHandler: new FetchHttpHandler({ + fetchFunction: this.config.fetchFunction + }), + beaconRequestHandler: new BeaconHttpHandler(), + endpoint, + region, + credentials + }); + }; +} diff --git a/src/dispatch/EnhancedAuthentication.ts b/src/dispatch/EnhancedAuthentication.ts new file mode 100644 index 00000000..a2b72350 --- /dev/null +++ b/src/dispatch/EnhancedAuthentication.ts @@ -0,0 +1,116 @@ +import { + CognitoIdentityClient, + fromCognitoIdentityPool +} from './CognitoIdentityClient'; +import { CRED_COOKIE_NAME } from '../utils/constants'; +import { Config } from '../orchestration/Orchestration'; +import { CredentialProvider, Credentials } from '@aws-sdk/types'; +import { FetchHttpHandler } from '@aws-sdk/fetch-http-handler'; +import { storeCookie, getCookie } from '../utils/cookies-utils'; + +export class EnhancedAuthentication { + private cognitoIdentityClient: CognitoIdentityClient; + private config: Config; + + constructor(config: Config) { + const region: string = config.identityPoolId.split(':')[0]; + this.config = config; + this.cognitoIdentityClient = new CognitoIdentityClient({ + fetchRequestHandler: new FetchHttpHandler(), + region + }); + } + + /** + * Provides credentials for an anonymous (guest) user. These credentials are retrieved from the first successful + * provider in a chain. + * + * Credentials are stored in and retrieved from a non-HttpOnly cookie. This prevents the client from having to + * re-authenticate every time the client loads, which (1) improves the performance of the RUM web client and (2) + * reduces the load on AWS services Cognito and STS. + * + * While storing credentials in a non-HttpOnly cookie puts the cookie at greater risk of being leaked through an + * XSS attack, there is no impact if the credentials were to be leaked. This is because (1) the identity pool ID + * and role ARN are public and (2) the credentials are for an anonymous (guest) user. + * + * Regarding (1), the identity pool ID and role ARN are, by necessity, public. These identifiers are shipped with + * each application as part of Cognito's Basic (Classic) authentication flow. The identity pool ID and role ARN + * are not secret. + * + * Regarding (2), the authentication chain implemented in this file only supports anonymous (guest) + * authentication. When the Cognito authentication flow is executed, {@code AnonymousCognitoCredentialsProvider} + * does not communicate with a login provider such as Amazon, Facebook or Google. Instead, it relies on (a) the + * identity pool supporting unauthenticated identities and (b) the IAM role policy enabling login through the + * identity pool. If the identity pool does not support unauthenticated identities, this authentication chain + * will not succeed. + * + * Taken together, (1) and (2) mean that if these temporary credentials were to be leaked, the leaked credentials + * would not allow a bad actor to gain access to anything which they did not already have public access to. + * + * Implements CredentialsProvider = Provider + */ + public ChainAnonymousCredentialsProvider = async (): Promise => { + return this.AnonymousCookieCredentialsProvider().catch( + this.AnonymousCognitoCredentialsProvider + ); + }; + + /** + * Provides credentials for an anonymous (guest) user. These credentials are read from a cookie. + * + * Implements CredentialsProvider = Provider + */ + private AnonymousCookieCredentialsProvider = async (): Promise => { + return new Promise((resolve, reject) => { + const credString = getCookie(CRED_COOKIE_NAME); + if (credString && this.useCookies() && atob) { + let credentials; + try { + credentials = JSON.parse(atob(credString)); + } catch (e) { + // Error decoding or parsing the cookie -- abort + reject(); + } + // The expiration property of Credentials has a date type. Because the date was serialized as a string, + // we need to convert it back into a date, otherwise the AWS SDK signing middleware + // (@aws-sdk/middleware-signing) will throw an exception and no credentials will be returned. + credentials.expiration = new Date(credentials.expiration); + resolve(credentials); + } else { + reject(); + } + }); + }; + + /** + * Provides credentials for an anonymous (guest) user. These credentials are retrieved from Cognito's enhanced + * authflow. + * + * See https://docs.aws.amazon.com/cognito/latest/developerguide/authentication-flow.html + * + * Implements CredentialsProvider = Provider + */ + private AnonymousCognitoCredentialsProvider = async (): Promise => { + const credentialProvider: CredentialProvider = fromCognitoIdentityPool({ + client: this.cognitoIdentityClient, + identityPoolId: this.config.identityPoolId as string + }); + + return credentialProvider().then((credentials) => { + if (btoa) { + storeCookie( + CRED_COOKIE_NAME, + btoa(JSON.stringify(credentials)), + undefined, + undefined, + credentials.expiration + ); + } + return credentials; + }); + }; + + private useCookies() { + return navigator.cookieEnabled && this.config.allowCookies; + } +} diff --git a/src/dispatch/FetchHttpHandler.ts b/src/dispatch/FetchHttpHandler.ts new file mode 100644 index 00000000..948481c0 --- /dev/null +++ b/src/dispatch/FetchHttpHandler.ts @@ -0,0 +1,137 @@ +import { HttpHandler, HttpRequest, HttpResponse } from '@aws-sdk/protocol-http'; +import { buildQueryString } from '@aws-sdk/querystring-builder'; +import { HeaderBag, HttpHandlerOptions } from '@aws-sdk/types'; + +import { requestTimeout } from './request-timeout'; + +declare let AbortController: any; + +/** + * Represents the http options that can be passed to a browser http client. + */ +export interface FetchHttpHandlerOptions { + /** + * The number of milliseconds a request can take before being automatically + * terminated. + */ + requestTimeout?: number; + + /** + * The function to use to execute the fetch request. + * + * Defaults to window.fetch if not provided. + */ + fetchFunction?: ( + input: RequestInfo, + init?: RequestInit + ) => Promise; +} + +export class FetchHttpHandler implements HttpHandler { + private readonly requestTimeout?: number; + private fetchFunction?: ( + input: RequestInfo, + init?: RequestInit + ) => Promise; + + constructor({ + fetchFunction, + requestTimeout + }: FetchHttpHandlerOptions = {}) { + this.requestTimeout = requestTimeout; + this.fetchFunction = fetchFunction; + } + + destroy(): void { + // Do nothing. TLS and HTTP/2 connection pooling is handled by the browser. + } + + handle( + request: HttpRequest, + { abortSignal }: HttpHandlerOptions = {} + ): Promise<{ response: HttpResponse }> { + const requestTimeoutInMs = this.requestTimeout; + + // if the request was already aborted, prevent doing extra work + if (abortSignal?.aborted) { + const abortError = new Error('Request aborted'); + abortError.name = 'AbortError'; + return Promise.reject(abortError); + } + + let path = request.path; + if (request.query) { + const queryString = buildQueryString(request.query); + if (queryString) { + path += `?${queryString}`; + } + } + + const { port, method } = request; + const url = `${request.protocol}//${request.hostname}${ + port ? `:${port}` : '' + }${path}`; + // Request constructor doesn't allow GET/HEAD request with body + // ref: https://github.com/whatwg/fetch/issues/551 + const body = + method === 'GET' || method === 'HEAD' ? undefined : request.body; + const requestOptions: RequestInit = { + body, + headers: new Headers(request.headers), + method + }; + + // some browsers support abort signal + if (typeof AbortController !== 'undefined') { + (requestOptions as any).signal = abortSignal; + } + + const fetchRequest = new Request(url, requestOptions); + const raceOfPromises = [ + this.fetchFunction + .apply(window, [fetchRequest]) + .then((response) => { + const fetchHeaders: any = response.headers; + const transformedHeaders: HeaderBag = {}; + + for (const pair of fetchHeaders.entries() as string[][]) { + transformedHeaders[pair[0]] = pair[1]; + } + + const hasReadableStream = response.body !== undefined; + + // Return the response with buffered body + if (!hasReadableStream) { + return response.blob().then((body) => ({ + response: new HttpResponse({ + headers: transformedHeaders, + statusCode: response.status, + body + }) + })); + } + // Return the response with streaming body + return { + response: new HttpResponse({ + headers: transformedHeaders, + statusCode: response.status, + body: response.body + }) + }; + }), + requestTimeout(requestTimeoutInMs) + ]; + if (abortSignal) { + raceOfPromises.push( + new Promise((resolve, reject) => { + abortSignal.onabort = () => { + const abortError = new Error('Request aborted'); + abortError.name = 'AbortError'; + reject(abortError); + }; + }) + ); + } + return Promise.race(raceOfPromises); + } +} diff --git a/src/dispatch/StsClient.ts b/src/dispatch/StsClient.ts new file mode 100644 index 00000000..9197b833 --- /dev/null +++ b/src/dispatch/StsClient.ts @@ -0,0 +1,80 @@ +import { HttpHandler, HttpRequest } from '@aws-sdk/protocol-http'; +import { CognitoIdentityClientConfig } from './CognitoIdentityClient'; + +const METHOD: string = 'POST'; +const CONTENT_TYPE: string = 'application/x-www-form-urlencoded'; +const PROTOCOL: string = 'https:'; +const ACTION: string = 'AssumeRoleWithWebIdentity'; +const VERSION: string = '2011-06-15'; + +export interface STSSendRequest { + RoleArn: string; + RoleSessionName: string; + WebIdentityToken: string; +} + +export class StsClient { + private fetchRequestHandler: HttpHandler; + private hostname: string; + + constructor(config: CognitoIdentityClientConfig) { + this.hostname = `sts.${config.region}.amazonaws.com`; + this.fetchRequestHandler = config.fetchRequestHandler; + } + + public assumeRoleWithWebIdentity = async (request: STSSendRequest) => { + const requestObject = { + ...request, + Action: ACTION, + Version: VERSION + }; + const encodedBody = new URLSearchParams( + Object.entries(requestObject) + ).toString(); + + const STSRequest = new HttpRequest({ + method: METHOD, + headers: { + 'content-type': CONTENT_TYPE, + host: this.hostname + }, + protocol: PROTOCOL, + hostname: this.hostname, + body: encodedBody + }); + + return this.fetchRequestHandler + .handle(STSRequest) + .then(({ response }) => + response.body + .getReader() + .read() + .then(({ value }) => { + const xmlResponse = String.fromCharCode.apply( + null, + value + ); + + return { + accessKeyId: xmlResponse + .split('')[1] + .split('')[0], + secretAccessKey: xmlResponse + .split('')[1] + .split('')[0], + sessionToken: xmlResponse + .split('')[1] + .split('')[0], + expiration: new Date( + xmlResponse + .split('')[1] + .split('')[0] + ) + }; + }) + ) + .catch(() => { + throw new Error('CWR: Failed to retrieve credentials from STS'); + }); + }; +} diff --git a/src/dispatch/__tests__/Authentication.test.ts b/src/dispatch/__tests__/Authentication.test.ts new file mode 100644 index 00000000..903d78c2 --- /dev/null +++ b/src/dispatch/__tests__/Authentication.test.ts @@ -0,0 +1,298 @@ +import { Authentication } from '../Authentication'; +import { CRED_COOKIE_NAME } from '../../utils/constants'; +import { defaultConfig } from '../../orchestration/Orchestration'; +import { removeCookie, storeCookie } from '../../utils/cookies-utils'; + +const assumeRole = jest.fn(); +const mockGetId = jest.fn(); +const mockGetIdToken = jest.fn(); + +jest.mock('../CognitoIdentityClient', () => ({ + CognitoIdentityClient: jest.fn().mockImplementation(() => ({ + getId: mockGetId, + getOpenIdToken: mockGetIdToken + })) +})); + +jest.mock('../StsClient', () => ({ + StsClient: jest.fn().mockImplementation(() => ({ + assumeRoleWithWebIdentity: assumeRole + })) +})); + +const IDENTITY_POOL_ID = 'us-west-2:a-b-c-d'; +const GUEST_ROLE_ARN = 'arn:aws:iam::123:role/Unauth'; + +describe('Authentication tests', () => { + beforeEach(() => { + // @ts-ignore + mockGetId.mockReset(); + // @ts-ignore + mockGetIdToken.mockReset(); + // @ts-ignore + assumeRole.mockReset(); + mockGetId.mockResolvedValue({ + IdentityId: 'mock' + }); + mockGetIdToken.mockResolvedValue({ + RoleArn: 'mockArn', + RoleSessionName: 'mockName', + WebIdentityToken: 'mockToken' + }); + assumeRole.mockResolvedValue({ + accessKeyId: 'x', + secretAccessKey: 'y', + sessionToken: 'z' + }); + removeCookie(CRED_COOKIE_NAME); + }); + + // tslint:disable-next-line:max-line-length + test('when auth cookie is in the store then authentication chain retrieves credentials from cookie', async () => { + // Init + const auth = new Authentication({ + ...defaultConfig, + ...{ + allowCookies: true, + identityPoolId: IDENTITY_POOL_ID, + guestRoleArn: GUEST_ROLE_ARN + } + }); + + storeCookie( + CRED_COOKIE_NAME, + btoa( + JSON.stringify({ + accessKeyId: 'a', + secretAccessKey: 'b', + sessionToken: 'c' + }) + ) + ); + + // Run + const credentials = await auth.ChainAnonymousCredentialsProvider(); + + // Assert + expect(credentials).toEqual( + expect.objectContaining({ + accessKeyId: 'a', + secretAccessKey: 'b', + sessionToken: 'c' + }) + ); + }); + + // tslint:disable-next-line:max-line-length + test('when auth cookie corrupt then authentication chain retrieves credentials from basic authflow', async () => { + // Init + const auth = new Authentication({ + ...defaultConfig, + ...{ + allowCookies: true, + identityPoolId: IDENTITY_POOL_ID, + guestRoleArn: GUEST_ROLE_ARN + } + }); + + storeCookie( + CRED_COOKIE_NAME, + JSON.stringify({ + accessKeyId: 'a', + secretAccessKey: 'b', + sessionToken: 'c' + }) + ); + + // Run + const credentials = await auth.ChainAnonymousCredentialsProvider(); + + // Assert + expect(credentials).toEqual( + expect.objectContaining({ + accessKeyId: 'x', + secretAccessKey: 'y', + sessionToken: 'z' + }) + ); + }); + + // tslint:disable-next-line:max-line-length + test('when auth cookie is not in the store authentication chain retrieves credentials from basic authflow', async () => { + // Init + const auth = new Authentication({ + ...defaultConfig, + ...{ + allowCookies: true, + identityPoolId: IDENTITY_POOL_ID, + guestRoleArn: GUEST_ROLE_ARN + } + }); + + // Run + const credentials = await auth.ChainAnonymousCredentialsProvider(); + + // Assert + expect(credentials).toEqual( + expect.objectContaining({ + accessKeyId: 'x', + secretAccessKey: 'y', + sessionToken: 'z' + }) + ); + }); + + // tslint:disable-next-line:max-line-length + test('when cookies are not allowed then authentication chain retrieves credentials from basic authflow', async () => { + // Init + const auth = new Authentication({ + ...defaultConfig, + ...{ + allowCookies: false, + identityPoolId: IDENTITY_POOL_ID, + guestRoleArn: GUEST_ROLE_ARN + } + }); + storeCookie(CRED_COOKIE_NAME, 'a:b:c'); + + // Run + const credentials = await auth.ChainAnonymousCredentialsProvider(); + + // Assert + expect(credentials).toEqual( + expect.objectContaining({ + accessKeyId: 'x', + secretAccessKey: 'y', + sessionToken: 'z' + }) + ); + }); + + // tslint:disable-next-line:max-line-length + test('when cookie expires then authentication chain retrieves credentials from basic authflow', async () => { + // Init + const auth = new Authentication({ + ...defaultConfig, + ...{ + allowCookies: true, + identityPoolId: IDENTITY_POOL_ID, + guestRoleArn: GUEST_ROLE_ARN + } + }); + storeCookie( + CRED_COOKIE_NAME, + 'a:b:c', + undefined, + undefined, + new Date(0) + ); + + // Run + const credentials = await auth.ChainAnonymousCredentialsProvider(); + + // Assert + expect(credentials).toEqual( + expect.objectContaining({ + accessKeyId: 'x', + secretAccessKey: 'y', + sessionToken: 'z' + }) + ); + }); + + // tslint:disable-next-line:max-line-length + test('when credential is retrieved from basic auth then next credential is retrieved from cookie store', async () => { + // Init + const expiration = new Date(Date.now() + 3600 * 1000); + assumeRole + .mockResolvedValueOnce({ + accessKeyId: 'a', + expiration, + secretAccessKey: 'b', + sessionToken: 'c' + }) + .mockResolvedValueOnce({ + accessKeyId: 'x', + expiration, + secretAccessKey: 'y', + sessionToken: 'z' + }); + + const auth = new Authentication({ + ...defaultConfig, + ...{ + allowCookies: true, + identityPoolId: IDENTITY_POOL_ID, + guestRoleArn: GUEST_ROLE_ARN + } + }); + + // Run + await auth.ChainAnonymousCredentialsProvider(); + const credentials = await auth.ChainAnonymousCredentialsProvider(); + + // Assert + expect(credentials).toEqual( + expect.objectContaining({ + accessKeyId: 'a', + secretAccessKey: 'b', + sessionToken: 'c', + expiration + }) + ); + }); + + test('when assumeRole fails then throw error', async () => { + assumeRole.mockImplementation(() => { + throw new Error('assumeRole error'); + }); + // Init + const auth = new Authentication({ + ...defaultConfig, + ...{ + allowCookies: true, + identityPoolId: IDENTITY_POOL_ID, + guestRoleArn: GUEST_ROLE_ARN + } + }); + + // Assert + expect(auth.ChainAnonymousCredentialsProvider()).toThrowError; + }); + + test('when mockGetId fails then throw error', async () => { + mockGetId.mockImplementation(() => { + throw new Error('mockGetId error'); + }); + // Init + const auth = new Authentication({ + ...defaultConfig, + ...{ + allowCookies: true, + identityPoolId: IDENTITY_POOL_ID, + guestRoleArn: GUEST_ROLE_ARN + } + }); + + // Assert + expect(auth.ChainAnonymousCredentialsProvider()).toThrowError; + }); + + test('when mockGetIdToken fails then throw error', async () => { + mockGetIdToken.mockImplementation(() => { + throw new Error('mockGetId error'); + }); + // Init + const auth = new Authentication({ + ...defaultConfig, + ...{ + allowCookies: true, + identityPoolId: IDENTITY_POOL_ID, + guestRoleArn: GUEST_ROLE_ARN + } + }); + + // Assert + expect(auth.ChainAnonymousCredentialsProvider()).toThrowError; + }); +}); diff --git a/src/dispatch/__tests__/BeaconHttpHandler.test.ts b/src/dispatch/__tests__/BeaconHttpHandler.test.ts new file mode 100644 index 00000000..11a487a3 --- /dev/null +++ b/src/dispatch/__tests__/BeaconHttpHandler.test.ts @@ -0,0 +1,81 @@ +import * as Utils from '../../test-utils/test-utils'; +import { BeaconHttpHandler } from '../BeaconHttpHandler'; +import { DataPlaneClient } from '../DataPlaneClient'; +import { HttpResponse } from '@aws-sdk/protocol-http'; +import { advanceTo } from 'jest-date-mock'; + +const sendBeacon = jest.fn(() => true); +global.navigator.sendBeacon = sendBeacon; + +describe('BeaconHttpHandler tests', () => { + beforeEach(() => { + advanceTo(0); + sendBeacon.mockClear(); + }); + + test('when sendBeacon succeeds then HttpResponse status is 200', async () => { + // Init + const beaconHandler = new BeaconHttpHandler(); + const client: DataPlaneClient = new DataPlaneClient({ + fetchRequestHandler: undefined, + beaconRequestHandler: beaconHandler, + endpoint: Utils.AWS_RUM_ENDPOINT, + region: Utils.AWS_RUM_REGION, + credentials: Utils.createAwsCredentials() + }); + + // Run + // @ts-ignore + const response: HttpResponse = ( + await client.sendBeacon(Utils.LOG_EVENTS_REQUEST) + ).response; + + // Assert + expect(response.statusCode).toEqual(200); + }); + + test('when sendBeacon fails then promise is rejected', async () => { + // Init + const beaconHandler = new BeaconHttpHandler(); + const client: DataPlaneClient = new DataPlaneClient({ + fetchRequestHandler: undefined, + beaconRequestHandler: beaconHandler, + endpoint: Utils.AWS_RUM_ENDPOINT, + region: Utils.AWS_RUM_REGION, + credentials: Utils.createAwsCredentials() + }); + + // Run + // @ts-ignore + const response: Promise<{ response: HttpResponse }> = client.sendBeacon( + Utils.LOG_EVENTS_REQUEST + ); + // Assert + expect(response).rejects.toEqual(undefined); + }); + + test('sendBeacon builds correct url', async () => { + // Init + const beaconHandler = new BeaconHttpHandler(); + const client: DataPlaneClient = new DataPlaneClient({ + fetchRequestHandler: undefined, + beaconRequestHandler: beaconHandler, + endpoint: Utils.AWS_RUM_ENDPOINT, + region: Utils.AWS_RUM_REGION, + credentials: Utils.createAwsCredentials() + }); + + // Run + // @ts-ignore + const response: HttpResponse = ( + await client.sendBeacon(Utils.LOG_EVENTS_REQUEST) + ).response; + + // Assert + // @ts-ignore + const url: string = sendBeacon.mock.calls[0][0]; + expect(url).toContain( + 'https://rumservicelambda.us-west-2.amazonaws.com/application/application123/events?X-Amz-Algorithm=AWS4-HMAC-SHA256' + ); + }); +}); diff --git a/src/dispatch/__tests__/CognitoIdentityClient.test.ts b/src/dispatch/__tests__/CognitoIdentityClient.test.ts new file mode 100644 index 00000000..ec80afda --- /dev/null +++ b/src/dispatch/__tests__/CognitoIdentityClient.test.ts @@ -0,0 +1,171 @@ +import * as Utils from '../../test-utils/test-utils'; +import { FetchHttpHandler } from '@aws-sdk/fetch-http-handler'; +import { advanceTo } from 'jest-date-mock'; +import { CognitoIdentityClient } from '../CognitoIdentityClient'; +import { Credentials } from '@aws-sdk/types'; +import { getReadableStream } from '../../test-utils/test-utils'; + +const mockCredentials: string = + '{ "IdentityId": "a", "Credentials": { "AccessKeyId": "x", "SecretAccessKey": "y", "SessionToken": "z" } }'; +const mockToken: string = '{"IdentityId": "mockId", "Token": "mockToken"}'; +const mockIdCommand: string = '{"IdentityId": "mockId"}'; + +const fetchHandler = jest.fn(); + +jest.mock('@aws-sdk/fetch-http-handler', () => ({ + FetchHttpHandler: jest + .fn() + .mockImplementation(() => ({ handle: fetchHandler })) +})); + +describe('CognitoIdentityClient tests', () => { + beforeEach(() => { + advanceTo(0); + fetchHandler.mockClear(); + + // @ts-ignore + FetchHttpHandler.mockImplementation(() => { + return { + handle: fetchHandler + }; + }); + }); + + test('when getCredentialsForIdentity called then credentials are returned', async () => { + fetchHandler.mockResolvedValueOnce({ + response: { + body: getReadableStream(mockCredentials) + } + }); + + // Init + const client: CognitoIdentityClient = new CognitoIdentityClient({ + fetchRequestHandler: new FetchHttpHandler(), + region: Utils.AWS_RUM_REGION + }); + + // Run + const creds: Credentials = await client.getCredentialsForIdentity( + 'my-fake-identity-id' + ); + + // Assert + expect(fetchHandler).toHaveBeenCalledTimes(1); + expect(creds).toMatchObject({ + accessKeyId: 'x', + secretAccessKey: 'y', + sessionToken: 'z' + }); + }); + + test('when getCredentialsForIdentity error, then an error is thrown', async () => { + // @ts-ignore + fetchHandler.mockImplementation(() => { + throw new Error('There are no credentials'); + }); + + // Init + const client: CognitoIdentityClient = new CognitoIdentityClient({ + fetchRequestHandler: new FetchHttpHandler(), + region: Utils.AWS_RUM_REGION + }); + + // Assert + expect(client.getCredentialsForIdentity('my-fake-identity-id')) + .toThrowError; + expect(fetchHandler).toHaveBeenCalledTimes(1); + }); + + test('when getOpenIdToken is called, then token command is returned', async () => { + fetchHandler.mockResolvedValueOnce({ + response: { + body: getReadableStream(mockToken) + } + }); + + // Init + const client: CognitoIdentityClient = new CognitoIdentityClient({ + fetchRequestHandler: new FetchHttpHandler(), + region: Utils.AWS_RUM_REGION + }); + + // Run + const tokenCommand = await client.getOpenIdToken({ + IdentityId: 'my-fake-identity-id' + }); + + // Assert + expect(fetchHandler).toHaveBeenCalledTimes(1); + expect(tokenCommand).toMatchObject({ + IdentityId: 'mockId', + Token: 'mockToken' + }); + }); + + test('when getOpenIdToken error, then an error is thrown', async () => { + // @ts-ignore + fetchHandler.mockImplementation(() => { + throw new Error('There are no credentials'); + }); + + // Init + const client: CognitoIdentityClient = new CognitoIdentityClient({ + fetchRequestHandler: new FetchHttpHandler(), + region: Utils.AWS_RUM_REGION + }); + + // Assert + expect( + client.getOpenIdToken({ + IdentityId: 'my-fake-identity-id' + }) + ).toThrowError; + expect(fetchHandler).toHaveBeenCalledTimes(1); + }); + + test('when getId is called, then token command is returned', async () => { + fetchHandler.mockResolvedValueOnce({ + response: { + body: getReadableStream(mockIdCommand) + } + }); + + // Init + const client: CognitoIdentityClient = new CognitoIdentityClient({ + fetchRequestHandler: new FetchHttpHandler(), + region: Utils.AWS_RUM_REGION + }); + + // Run + const idCommand = await client.getId({ + IdentityPoolId: 'my-fake-identity-pool-id' + }); + + // Assert + expect(fetchHandler).toHaveBeenCalledTimes(1); + expect(idCommand).toMatchObject({ + IdentityId: 'mockId' + }); + }); + + test('when getId error, then an error is thrown', async () => { + // @ts-ignore + fetchHandler.mockImplementation(() => { + throw new Error('There are no credentials'); + }); + + // Init + const client: CognitoIdentityClient = new CognitoIdentityClient({ + fetchRequestHandler: new FetchHttpHandler(), + region: Utils.AWS_RUM_REGION + }); + + // Assert + expect( + client.getId({ + IdentityPoolId: 'my-fake-identity-pool-id' + }) + ).toThrowError; + expect(fetchHandler).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/dispatch/__tests__/DataPlaneClient.test.ts b/src/dispatch/__tests__/DataPlaneClient.test.ts new file mode 100644 index 00000000..bb512cd7 --- /dev/null +++ b/src/dispatch/__tests__/DataPlaneClient.test.ts @@ -0,0 +1,135 @@ +import * as Utils from '../../test-utils/test-utils'; +import { BeaconHttpHandler } from '../BeaconHttpHandler'; +import { FetchHttpHandler } from '@aws-sdk/fetch-http-handler'; +import { DataPlaneClient } from '../DataPlaneClient'; +import { HttpRequest } from '@aws-sdk/protocol-http'; +import { advanceTo } from 'jest-date-mock'; + +const beaconHandler = jest.fn(() => Promise.resolve()); +jest.mock('../BeaconHttpHandler', () => ({ + BeaconHttpHandler: jest + .fn() + .mockImplementation(() => ({ handle: beaconHandler })) +})); +const fetchHandler = jest.fn(() => Promise.resolve()); +jest.mock('@aws-sdk/fetch-http-handler', () => ({ + FetchHttpHandler: jest + .fn() + .mockImplementation(() => ({ handle: fetchHandler })) +})); + +describe('DataPlaneClient tests', () => { + beforeEach(() => { + advanceTo(0); + beaconHandler.mockClear(); + fetchHandler.mockClear(); + + // @ts-ignore + BeaconHttpHandler.mockImplementation(() => { + return { + handle: beaconHandler + }; + }); + + // @ts-ignore + FetchHttpHandler.mockImplementation(() => { + return { + handle: fetchHandler + }; + }); + }); + + test('when sendFetch is used then fetch handler is used', async () => { + // Init + const client: DataPlaneClient = new DataPlaneClient({ + fetchRequestHandler: new FetchHttpHandler(), + beaconRequestHandler: new BeaconHttpHandler(), + endpoint: Utils.AWS_RUM_ENDPOINT, + region: Utils.AWS_RUM_REGION, + credentials: Utils.createAwsCredentials() + }); + + // Run + await client.sendFetch(Utils.LOG_EVENTS_REQUEST); + + // Assert + expect(fetchHandler).toHaveBeenCalledTimes(1); + }); + + test('when sendFetch is used then request contains correct signature header', async () => { + // Init + const client: DataPlaneClient = new DataPlaneClient({ + fetchRequestHandler: new FetchHttpHandler(), + beaconRequestHandler: new BeaconHttpHandler(), + endpoint: Utils.AWS_RUM_ENDPOINT, + region: Utils.AWS_RUM_REGION, + credentials: Utils.createAwsCredentials() + }); + + // Run + await client.sendFetch(Utils.LOG_EVENTS_REQUEST); + + // Assert + // @ts-ignore + const signedRequest: HttpRequest = fetchHandler.mock.calls[0][0]; + expect(signedRequest.headers['x-amz-date']).toEqual('19700101T000000Z'); + expect(signedRequest.headers['X-Amz-Content-Sha256']).toEqual( + '396cba73944df10e0fa9919af498b340ab0230f953ce1378a9a620681e767425' + ); + expect(signedRequest.headers['authorization']).toEqual( + 'AWS4-HMAC-SHA256 Credential=abc123/19700101/us-west-2/rum/aws4_request, SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=3148cd0affbd3bb2b160d1f36a43f146e642783ee3710451de9eac4a78974565' + ); + }); + + test('when sendBeacon is used then beacon handler is used', async () => { + // Init + const client: DataPlaneClient = new DataPlaneClient({ + fetchRequestHandler: new FetchHttpHandler(), + beaconRequestHandler: new BeaconHttpHandler(), + endpoint: Utils.AWS_RUM_ENDPOINT, + region: Utils.AWS_RUM_REGION, + credentials: Utils.createAwsCredentials() + }); + + // Run + await client.sendBeacon(Utils.LOG_EVENTS_REQUEST); + + // Assert + expect(beaconHandler).toHaveBeenCalledTimes(1); + }); + + test('when sendBeacon is used then request contains correct pre-signed url', async () => { + // Init + const client: DataPlaneClient = new DataPlaneClient({ + fetchRequestHandler: new FetchHttpHandler(), + beaconRequestHandler: new BeaconHttpHandler(), + endpoint: Utils.AWS_RUM_ENDPOINT, + region: Utils.AWS_RUM_REGION, + credentials: Utils.createAwsCredentials() + }); + + // Run + await client.sendBeacon(Utils.LOG_EVENTS_REQUEST); + + // Assert + // @ts-ignore + const signedRequest: HttpRequest = beaconHandler.mock.calls[0][0]; + expect(signedRequest.query['X-Amz-Algorithm']).toEqual( + 'AWS4-HMAC-SHA256' + ); + expect(signedRequest.query['X-Amz-Content-Sha256']).toEqual( + '396cba73944df10e0fa9919af498b340ab0230f953ce1378a9a620681e767425' + ); + expect(signedRequest.query['X-Amz-Credential']).toEqual( + 'abc123/19700101/us-west-2/rum/aws4_request' + ); + expect(signedRequest.query['X-Amz-Date']).toEqual('19700101T000000Z'); + expect(signedRequest.query['X-Amz-Expires']).toEqual('60'); + expect(signedRequest.query['X-Amz-SignedHeaders']).toEqual( + 'content-type;host' + ); + expect(signedRequest.query['X-Amz-Signature']).toEqual( + 'ba005a3be8cbc901e63fca2e83d257a76f45d13e9511df83f73a9ff9f2e23dfb' + ); + }); +}); diff --git a/src/dispatch/__tests__/Dispatch.test.ts b/src/dispatch/__tests__/Dispatch.test.ts new file mode 100644 index 00000000..4e2d17a6 --- /dev/null +++ b/src/dispatch/__tests__/Dispatch.test.ts @@ -0,0 +1,319 @@ +import { Dispatch } from '../Dispatch'; +import * as Utils from '../../test-utils/test-utils'; +import { DataPlaneClient } from '../DataPlaneClient'; +import { CredentialProvider } from '@aws-sdk/types'; +import { defaultConfig } from '../../orchestration/Orchestration'; + +const sendFetch = jest.fn(() => Promise.resolve()); +const sendBeacon = jest.fn(() => Promise.resolve()); +jest.mock('../DataPlaneClient', () => ({ + DataPlaneClient: jest + .fn() + .mockImplementation(() => ({ sendFetch, sendBeacon })) +})); + +const APPLICATION_ID = 'abc123'; + +describe('Dispatch tests', () => { + beforeEach(() => { + sendFetch.mockClear(); + sendBeacon.mockClear(); + + // @ts-ignore + DataPlaneClient.mockImplementation(() => { + return { + sendFetch, + sendBeacon + }; + }); + }); + + test('dispatch() sends data through client', async () => { + // Init + const dispatch = new Dispatch( + APPLICATION_ID, + Utils.AWS_RUM_REGION, + Utils.AWS_RUM_ENDPOINT, + Utils.createDefaultEventCacheWithEvents(), + { + ...defaultConfig, + ...{ dispatchInterval: Utils.AUTO_DISPATCH_OFF } + } + ); + dispatch.setAwsCredentials(Utils.createAwsCredentials()); + + // Run + await expect(dispatch.dispatchFetch()).resolves.toBe(undefined); + + // Assert + expect(DataPlaneClient).toHaveBeenCalled(); + expect(sendFetch).toHaveBeenCalledTimes(1); + }); + + test('when CredentialProvider is used then credentials are immediately fetched', async () => { + // Init + const credentialProvider: CredentialProvider = jest.fn(); + const dispatch = new Dispatch( + APPLICATION_ID, + Utils.AWS_RUM_REGION, + Utils.AWS_RUM_ENDPOINT, + Utils.createDefaultEventCacheWithEvents(), + { + ...defaultConfig, + ...{ dispatchInterval: Utils.AUTO_DISPATCH_OFF } + } + ); + + // Run + dispatch.setAwsCredentials(credentialProvider); + + // Assert + expect(credentialProvider).toHaveBeenCalledTimes(1); + }); + + test('dispatch() throws exception when LogEventsCommand fails', async () => { + // Init + const sendFetch = jest.fn(() => + Promise.reject('Something went wrong.') + ); + // @ts-ignore + DataPlaneClient.mockImplementation(() => { + return { + sendFetch + }; + }); + + const dispatch = new Dispatch( + APPLICATION_ID, + Utils.AWS_RUM_REGION, + Utils.AWS_RUM_ENDPOINT, + Utils.createDefaultEventCacheWithEvents(), + { + ...defaultConfig, + ...{ dispatchInterval: Utils.AUTO_DISPATCH_OFF } + } + ); + dispatch.setAwsCredentials(Utils.createAwsCredentials()); + + // Run + // Assert + await expect(dispatch.dispatchFetch()).rejects.toEqual( + 'Something went wrong.' + ); + }); + + test('dispatch() does nothing when disabled', async () => { + // Init + const dispatch = new Dispatch( + APPLICATION_ID, + Utils.AWS_RUM_REGION, + Utils.AWS_RUM_ENDPOINT, + Utils.createDefaultEventCacheWithEvents(), + { + ...defaultConfig, + ...{ dispatchInterval: Utils.AUTO_DISPATCH_OFF } + } + ); + dispatch.setAwsCredentials(Utils.createAwsCredentials()); + + // Run + dispatch.disable(); + await dispatch.dispatchFetch(); + + // Assert + expect(DataPlaneClient).toHaveBeenCalled(); + expect(sendFetch).toHaveBeenCalledTimes(0); + }); + + test('dispatch() sends when disabled then enabled', async () => { + // Init + const dispatch = new Dispatch( + APPLICATION_ID, + Utils.AWS_RUM_REGION, + Utils.AWS_RUM_ENDPOINT, + Utils.createDefaultEventCacheWithEvents(), + { + ...defaultConfig, + ...{ dispatchInterval: Utils.AUTO_DISPATCH_OFF } + } + ); + dispatch.setAwsCredentials(Utils.createAwsCredentials()); + + // Run + dispatch.disable(); + dispatch.enable(); + await dispatch.dispatchFetch(); + + // Assert + expect(DataPlaneClient).toHaveBeenCalled(); + expect(sendFetch).toHaveBeenCalledTimes(1); + }); + + test('dispatch() automatically dispatches when interval > 0', async () => { + // Init + const dispatch = new Dispatch( + APPLICATION_ID, + Utils.AWS_RUM_REGION, + Utils.AWS_RUM_ENDPOINT, + Utils.createDefaultEventCacheWithEvents(), + { + ...defaultConfig, + ...{ dispatchInterval: 1 } + } + ); + dispatch.setAwsCredentials(Utils.createAwsCredentials()); + + // Run + await new Promise((resolve) => + window.setTimeout(() => resolve(undefined), 1) + ); + + // Assert + expect(DataPlaneClient).toHaveBeenCalled(); + expect(sendFetch).toHaveBeenCalled(); + }); + + test('dispatch() does not automatically dispatch when interval = 0', async () => { + // Init + const dispatch = new Dispatch( + APPLICATION_ID, + Utils.AWS_RUM_REGION, + Utils.AWS_RUM_ENDPOINT, + Utils.createDefaultEventCacheWithEvents(), + { + ...defaultConfig, + ...{ dispatchInterval: Utils.AUTO_DISPATCH_OFF } + } + ); + dispatch.setAwsCredentials(Utils.createAwsCredentials()); + + // Run + await new Promise((resolve) => + window.setTimeout(() => resolve(undefined), 1) + ); + + // Assert + expect(DataPlaneClient).toHaveBeenCalled(); + expect(sendFetch).not.toHaveBeenCalled(); + }); + + test('dispatch() does not automatically dispatch when interval < 0', async () => { + // Init + const dispatch = new Dispatch( + APPLICATION_ID, + Utils.AWS_RUM_REGION, + Utils.AWS_RUM_ENDPOINT, + Utils.createDefaultEventCacheWithEvents(), + { + ...defaultConfig, + ...{ dispatchInterval: -1 } + } + ); + dispatch.setAwsCredentials(Utils.createAwsCredentials()); + + // Run + await new Promise((resolve) => + window.setTimeout(() => resolve(undefined), 1) + ); + + // Assert + expect(DataPlaneClient).toHaveBeenCalled(); + expect(sendFetch).not.toHaveBeenCalled(); + }); + + test('dispatch() does not automatically dispatch when dispatch is disabled', async () => { + // Init + const dispatch = new Dispatch( + APPLICATION_ID, + Utils.AWS_RUM_REGION, + Utils.AWS_RUM_ENDPOINT, + Utils.createDefaultEventCacheWithEvents(), + { + ...defaultConfig, + ...{ dispatchInterval: 1 } + } + ); + dispatch.setAwsCredentials(Utils.createAwsCredentials()); + dispatch.disable(); + + // Run + await new Promise((resolve) => + window.setTimeout(() => resolve(undefined), 1) + ); + + // Assert + expect(DataPlaneClient).toHaveBeenCalled(); + expect(sendFetch).not.toHaveBeenCalled(); + }); + + test('dispatch() resumes when disabled and enabled', async () => { + // Init + const dispatch = new Dispatch( + APPLICATION_ID, + Utils.AWS_RUM_REGION, + Utils.AWS_RUM_ENDPOINT, + Utils.createDefaultEventCacheWithEvents(), + { + ...defaultConfig, + ...{ dispatchInterval: 1 } + } + ); + dispatch.setAwsCredentials(Utils.createAwsCredentials()); + dispatch.disable(); + dispatch.enable(); + + // Run + await new Promise((resolve) => + window.setTimeout(() => resolve(undefined), 1) + ); + + // Assert + expect(DataPlaneClient).toHaveBeenCalled(); + expect(sendFetch).toHaveBeenCalled(); + }); + + test('when visibilitychange event is triggered then beacon dispatch runs', async () => { + // Init + const dispatch = new Dispatch( + APPLICATION_ID, + Utils.AWS_RUM_REGION, + Utils.AWS_RUM_ENDPOINT, + Utils.createDefaultEventCacheWithEvents(), + { + ...defaultConfig, + ...{ dispatchInterval: 1 } + } + ); + dispatch.setAwsCredentials(Utils.createAwsCredentials()); + dispatch.startDispatchTimer(); + + // Run + document.dispatchEvent(new Event('visibilitychange')); + + // Assert + expect(sendBeacon).toHaveBeenCalled(); + }); + + test('when plugin is disabled then beacon dispatch does not run', async () => { + // Init + const dispatch = new Dispatch( + APPLICATION_ID, + Utils.AWS_RUM_REGION, + Utils.AWS_RUM_ENDPOINT, + Utils.createDefaultEventCacheWithEvents(), + { + ...defaultConfig, + ...{ dispatchInterval: 1 } + } + ); + dispatch.setAwsCredentials(Utils.createAwsCredentials()); + dispatch.startDispatchTimer(); + dispatch.disable(); + + // Run + document.dispatchEvent(new Event('visibilitychange')); + + // Assert + expect(sendBeacon).not.toHaveBeenCalled(); + }); +}); diff --git a/src/dispatch/__tests__/EnhancedAuthentication.test.ts b/src/dispatch/__tests__/EnhancedAuthentication.test.ts new file mode 100644 index 00000000..730f9b63 --- /dev/null +++ b/src/dispatch/__tests__/EnhancedAuthentication.test.ts @@ -0,0 +1,294 @@ +import { CRED_COOKIE_NAME } from '../../utils/constants'; +import { Credentials } from '@aws-sdk/types'; +import { EnhancedAuthentication } from '../EnhancedAuthentication'; +import { defaultConfig } from '../../orchestration/Orchestration'; +import { fromCognitoIdentityPool } from '../CognitoIdentityClient'; +import { removeCookie, storeCookie } from '../../utils/cookies-utils'; + +const mockGetId = jest.fn(); +const getCredentials = jest.fn(); + +jest.mock('../CognitoIdentityClient', () => ({ + fromCognitoIdentityPool: jest.fn(), + CognitoIdentityClient: jest.fn().mockImplementation(() => ({ + getId: mockGetId, + getCredentialsForIdentity: getCredentials + })) +})); + +const IDENTITY_POOL_ID = 'us-west-2:a-b-c-d'; +const GUEST_ROLE_ARN = 'arn:aws:iam::123:role/Unauth'; + +describe('EnhancedAuthentication tests', () => { + beforeEach(() => { + // @ts-ignore + mockGetId.mockReset(); + // @ts-ignore + getCredentials.mockReset(); + mockGetId.mockResolvedValue({ + IdentityId: 'mock' + }); + getCredentials.mockResolvedValue({ + accessKeyId: 'x', + secretAccessKey: 'y', + sessionToken: 'z', + expiration: new Date(Date.now() + 3600 * 1000) + }); + // @ts-ignore + fromCognitoIdentityPool.mockReset(); + // @ts-ignore + fromCognitoIdentityPool.mockReturnValue( + () => + new Promise((resolve) => + resolve({ + accessKeyId: 'x', + secretAccessKey: 'y', + sessionToken: 'z', + expiration: new Date(Date.now() + 3600 * 1000) + }) + ) + ); + removeCookie(CRED_COOKIE_NAME); + }); + + // tslint:disable-next-line:max-line-length + test('when auth cookie is in the store then authentication chain retrieves credentials from cookie', async () => { + // Init + const auth = new EnhancedAuthentication({ + ...defaultConfig, + ...{ + allowCookies: true, + identityPoolId: IDENTITY_POOL_ID + } + }); + + storeCookie( + CRED_COOKIE_NAME, + btoa( + JSON.stringify({ + accessKeyId: 'a', + secretAccessKey: 'b', + sessionToken: 'c' + }) + ) + ); + + // Run + const credentials = await auth.ChainAnonymousCredentialsProvider(); + + // Assert + expect(credentials).toEqual( + expect.objectContaining({ + accessKeyId: 'a', + secretAccessKey: 'b', + sessionToken: 'c' + }) + ); + }); + + // tslint:disable-next-line:max-line-length + test('when auth cookie corrupt then authentication chain retrieves credentials from basic authflow', async () => { + // Init + const auth = new EnhancedAuthentication({ + ...defaultConfig, + ...{ + allowCookies: true, + identityPoolId: IDENTITY_POOL_ID, + guestRoleArn: GUEST_ROLE_ARN + } + }); + + storeCookie( + CRED_COOKIE_NAME, + JSON.stringify({ + accessKeyId: 'a', + secretAccessKey: 'b', + sessionToken: 'c' + }) + ); + + // Run + const credentials = await auth.ChainAnonymousCredentialsProvider(); + + // Assert + expect(credentials).toEqual( + expect.objectContaining({ + accessKeyId: 'x', + secretAccessKey: 'y', + sessionToken: 'z' + }) + ); + }); + + // tslint:disable-next-line:max-line-length + test('when auth cookie is not in the store authentication chain retrieves credentials from basic authflow', async () => { + // Init + const auth = new EnhancedAuthentication({ + ...defaultConfig, + ...{ + allowCookies: true, + identityPoolId: IDENTITY_POOL_ID + } + }); + + // Run + const credentials = await auth.ChainAnonymousCredentialsProvider(); + + // Assert + expect(credentials).toEqual( + expect.objectContaining({ + accessKeyId: 'x', + secretAccessKey: 'y', + sessionToken: 'z' + }) + ); + }); + + // tslint:disable-next-line:max-line-length + test('when cookies are not allowed then authentication chain retrieves credentials from basic authflow', async () => { + // Init + const auth = new EnhancedAuthentication({ + ...defaultConfig, + ...{ + allowCookies: false, + identityPoolId: IDENTITY_POOL_ID + } + }); + storeCookie(CRED_COOKIE_NAME, 'a:b:c'); + + // Run + const credentials = await auth.ChainAnonymousCredentialsProvider(); + + // Assert + expect(credentials).toEqual( + expect.objectContaining({ + accessKeyId: 'x', + secretAccessKey: 'y', + sessionToken: 'z' + }) + ); + }); + + // tslint:disable-next-line:max-line-length + test('when cookie expires then authentication chain retrieves credentials from basic authflow', async () => { + // Init + const auth = new EnhancedAuthentication({ + ...defaultConfig, + ...{ + allowCookies: true, + identityPoolId: IDENTITY_POOL_ID, + guestRoleArn: GUEST_ROLE_ARN + } + }); + storeCookie( + CRED_COOKIE_NAME, + 'a:b:c', + undefined, + undefined, + new Date(0) + ); + + // Run + const credentials = await auth.ChainAnonymousCredentialsProvider(); + + // Assert + expect(credentials).toEqual( + expect.objectContaining({ + accessKeyId: 'x', + secretAccessKey: 'y', + sessionToken: 'z' + }) + ); + }); + + // tslint:disable-next-line:max-line-length + test('when credential is retrieved from basic auth then next credential is retrieved from cookie store', async () => { + // Init + const expiration = new Date(Date.now() + 3600 * 1000); + fromCognitoIdentityPool + // @ts-ignore + .mockReturnValueOnce( + () => + new Promise((resolve) => + resolve({ + accessKeyId: 'a', + secretAccessKey: 'b', + sessionToken: 'c', + expiration + }) + ) + ) + .mockReturnValueOnce( + () => + new Promise((resolve) => + resolve({ + accessKeyId: 'x', + secretAccessKey: 'y', + sessionToken: 'z', + expiration + }) + ) + ); + + const auth = new EnhancedAuthentication({ + ...defaultConfig, + ...{ + allowCookies: true, + identityPoolId: IDENTITY_POOL_ID, + guestRoleArn: GUEST_ROLE_ARN + } + }); + + // Run + await auth.ChainAnonymousCredentialsProvider(); + const credentials = await auth.ChainAnonymousCredentialsProvider(); + + // Assert + expect(credentials).toEqual( + expect.objectContaining({ + accessKeyId: 'a', + secretAccessKey: 'b', + sessionToken: 'c', + expiration + }) + ); + }); + + test('when getCredentialsForIdentity fails then throw an error', async () => { + // Init + mockGetId.mockImplementation(() => { + throw new Error('mockGetId error'); + }); + + const auth = new EnhancedAuthentication({ + ...defaultConfig, + ...{ + allowCookies: true, + identityPoolId: IDENTITY_POOL_ID, + guestRoleArn: GUEST_ROLE_ARN + } + }); + + // Assert + expect(auth.ChainAnonymousCredentialsProvider()).toThrowError; + }); + + test('when getId fails then throw an error', async () => { + // Init + getCredentials.mockImplementation(() => { + throw new Error('mockGetId error'); + }); + + const auth = new EnhancedAuthentication({ + ...defaultConfig, + ...{ + allowCookies: true, + identityPoolId: IDENTITY_POOL_ID, + guestRoleArn: GUEST_ROLE_ARN + } + }); + + // Assert + expect(auth.ChainAnonymousCredentialsProvider()).toThrowError; + }); +}); diff --git a/src/dispatch/__tests__/StsClient.test.ts b/src/dispatch/__tests__/StsClient.test.ts new file mode 100644 index 00000000..c4843657 --- /dev/null +++ b/src/dispatch/__tests__/StsClient.test.ts @@ -0,0 +1,84 @@ +import * as Utils from '../../test-utils/test-utils'; +import { Credentials } from '@aws-sdk/types'; +import { FetchHttpHandler } from '@aws-sdk/fetch-http-handler'; +import { advanceTo } from 'jest-date-mock'; +import { getReadableStream } from '../../test-utils/test-utils'; +import { StsClient } from '../StsClient'; + +const mockCredentials: string = + 'xyz2020'; + +const fetchHandler = jest.fn(); + +jest.mock('@aws-sdk/fetch-http-handler', () => ({ + FetchHttpHandler: jest + .fn() + .mockImplementation(() => ({ handle: fetchHandler })) +})); + +describe('StsClient tests', () => { + beforeEach(() => { + advanceTo(0); + fetchHandler.mockClear(); + + // @ts-ignore + FetchHttpHandler.mockImplementation(() => { + return { + handle: fetchHandler + }; + }); + }); + + test('when send is called, then credentials are returned', async () => { + // Init + fetchHandler.mockResolvedValue({ + response: { + body: getReadableStream(mockCredentials) + } + }); + + const client: StsClient = new StsClient({ + fetchRequestHandler: new FetchHttpHandler(), + region: Utils.AWS_RUM_REGION + }); + + // Run + const creds: Credentials = await client.assumeRoleWithWebIdentity({ + RoleArn: 'mock-role-arn', + RoleSessionName: 'mock-session-name', + WebIdentityToken: 'mock-web-identity-token' + }); + + // Assert + expect(fetchHandler).toHaveBeenCalledTimes(1); + expect(creds).toMatchObject({ + accessKeyId: 'x', + secretAccessKey: 'y', + sessionToken: 'z', + expiration: new Date('2020') + }); + }); + + test('when STS fails, error is thrown', async () => { + // @ts-ignore + fetchHandler.mockImplementation(() => { + throw new Error('There are no STS credentials'); + }); + + // Init + const client: StsClient = new StsClient({ + fetchRequestHandler: new FetchHttpHandler(), + region: Utils.AWS_RUM_REGION + }); + + // Assert + expect( + client.assumeRoleWithWebIdentity({ + RoleArn: 'mock-role-arn', + RoleSessionName: 'mock-session-name', + WebIdentityToken: 'mock-web-identity-token' + }) + ).toThrowError; + expect(fetchHandler).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/dispatch/dataplane.ts b/src/dispatch/dataplane.ts new file mode 100644 index 00000000..69f433ed --- /dev/null +++ b/src/dispatch/dataplane.ts @@ -0,0 +1,38 @@ +// These are the type definitions for the CloudWatch RUM data plane API, and are +// equivalent to those in the CloudWatch RUM SDK. +// +// We have not used the CloudWatch RUM SDK due to its size. While we could still +// use the type definitions from the CloudWatch RUM SDK, we have made a copy of +// them here to completely remove the dependency on the CloudWatch RUM SDK, at +// least until it is publicly available. + +export interface LogEventsRequest { + applicationId: string | undefined; + batch: EventBatch | undefined; +} + +export interface EventBatch { + batchId: string | undefined; + application?: ApplicationDetails; + user: UserDetails | undefined; + events: Event[] | undefined; +} + +export interface ApplicationDetails { + name?: string; + id?: string; + version?: string; +} + +export interface UserDetails { + userId?: string; + sessionId?: string; +} + +export interface Event { + id: string | undefined; + timestamp: Date | undefined; + type: string | undefined; + metadata?: string; + details: string | undefined; +} diff --git a/src/dispatch/request-timeout.ts b/src/dispatch/request-timeout.ts new file mode 100644 index 00000000..0e32f7ed --- /dev/null +++ b/src/dispatch/request-timeout.ts @@ -0,0 +1,13 @@ +export const requestTimeout = (timeoutInMs = 0): Promise => { + return new Promise((resolve, reject) => { + if (timeoutInMs) { + setTimeout(() => { + const timeoutError = new Error( + `Request did not complete within ${timeoutInMs} ms` + ); + timeoutError.name = 'TimeoutError'; + reject(timeoutError); + }, timeoutInMs); + } + }); +}; diff --git a/src/errors/XhrError.ts b/src/errors/XhrError.ts new file mode 100644 index 00000000..555da113 --- /dev/null +++ b/src/errors/XhrError.ts @@ -0,0 +1,6 @@ +export class XhrError extends Error { + constructor(message: string) { + super(message); + this.name = 'XMLHttpRequest error'; + } +} diff --git a/src/event-cache/EventCache.ts b/src/event-cache/EventCache.ts new file mode 100644 index 00000000..c0b49a55 --- /dev/null +++ b/src/event-cache/EventCache.ts @@ -0,0 +1,235 @@ +import { Session, SessionManager } from '../sessions/SessionManager'; +import { v4 } from 'uuid'; +import { MetaData } from '../events/meta-data'; +import { Config } from '../orchestration/Orchestration'; +import { PageManager } from '../sessions/PageManager'; +import { + ApplicationDetails, + EventBatch, + UserDetails, + Event +} from '../dispatch/dataplane'; + +/** + * A cache which stores events generated by telemetry plugins. + * + * The event cache stores meta data and events until they are dispatched to the + * data plane. The event cache removes the oldest event once the cache is full + * and a new event is added. + */ +export class EventCache { + private applicationDetails: ApplicationDetails; + private config: Config; + + private events: Event[] = []; + + private sessionManager: SessionManager; + private pageManager: PageManager; + + private enabled: boolean; + + /** + * @param applicationDetails Application identity and version. + * @param batchLimit The maximum number of events that will be returned in a batch. + * @param eventCacheSize The maximum number of events the cache can contain before dropping events. + * @param sessionManager The sessionManager returns user id, session id and handles session timeout. + * @param pageManager The pageManager returns page id. + */ + constructor(applicationDetails: ApplicationDetails, config: Config) { + const applicationName = applicationDetails.name + ? applicationDetails.name + : ''; + this.applicationDetails = applicationDetails; + this.config = config; + this.enabled = true; + this.pageManager = new PageManager(config, this.recordEvent); + this.sessionManager = new SessionManager( + applicationName, + config, + this.recordSessionInitEvent, + this.pageManager + ); + + if (this.isCurrentUrlAllowed()) { + this.sessionManager.getSession(); + } + } + + /** + * The event cache will record new events or new meta data. + */ + public enable(): void { + this.enabled = true; + } + + /** + * The event cache will not record new events or new meta data. Events and + * meta data which are already in the cache will still be accessible. + */ + public disable(): void { + this.enabled = false; + } + + /** + * Update the current page interaction for the session. + */ + public recordPageView = (pageId: string) => { + if (this.isCurrentUrlAllowed()) { + // There may not be an active session. + this.sessionManager.getSession(); + this.pageManager.recordPageView(pageId); + } + }; + + /** + * Add an event to the cache and reset the session timer. + * + * If the session is being recorded, the event will be recorded. + * If the session is not being recorded, the event will not be recorded. + * + * @param type The event schema. + */ + public recordEvent = (type: string, eventData: object) => { + if (!this.enabled) { + return; + } + + if (this.isCurrentUrlAllowed()) { + const session: Session = this.sessionManager.getSession(); + this.sessionManager.incrementSessionEventCount(); + + if ( + session.record && + (session.eventCount <= this.config.sessionEventLimit || + this.config.sessionEventLimit <= 0) + ) { + // Only record the event if the session is being recorded. + this.addRecordToCache(type, eventData); + } + } + }; + + /** + * Returns the current session (1) if a session exists and (2) if the + * current URL is allowed. Returns undefined otherwise. + */ + public getSession = (): Session | undefined => { + if (this.isCurrentUrlAllowed()) { + return this.sessionManager.getSession(); + } + return undefined; + }; + + /** + * Returns true if there are one or more events in the cache. + */ + public hasEvents(): boolean { + return this.events.length !== 0; + } + + /** + * Removes and returns the next batch of events. + */ + public getEventBatch(): EventBatch { + const eventBatch: EventBatch = { + application: this.applicationDetails, + batchId: v4(), + user: this.getUserDetails(), + events: [] + }; + + if (this.events.length === 0) { + return eventBatch; + } + + if (this.events.length <= this.config.batchLimit) { + // Return all events. + eventBatch.events = this.events; + this.events = []; + } else { + // Dispatch the front of the array and retain the back of the array. + eventBatch.events = this.events.splice(0, this.config.batchLimit); + } + + return eventBatch; + } + + /** + * Add a session start event to the cache. + */ + private recordSessionInitEvent = ( + session: Session, + type: string, + eventData: object + ) => { + if (!this.enabled) { + return; + } + if (session.record) { + this.addRecordToCache(type, eventData); + } + }; + + /** + * Add an event to the cache. + * @param type The event schema. + */ + private addRecordToCache = (type: string, eventData: object) => { + if (!this.enabled) { + return; + } + + if (this.events.length === this.config.eventCacheSize) { + // Make room in the cache by dropping the oldest event. + this.events.shift(); + } + + // The data plane service model (i.e., LogEvents) does not adhere to the + // RUM agent data model, where sessions and pages are first class + // objects with their own attribute sets. Instead, we store session + // attributes and page attributes together as 'meta data'. + const metaData: MetaData = { + version: '1.0.0', + ...this.sessionManager.getAttributes(), + ...this.pageManager.getAttributes() + }; + + this.events.push({ + details: JSON.stringify(eventData), + id: v4(), + metadata: JSON.stringify(metaData), + timestamp: new Date(), + type + }); + }; + + /** + * Returns {@code true} if the current url matches one of the allowedPages + * and does not match any of the deniedPages; returns {@code false} + * otherwise. + */ + private isCurrentUrlAllowed() { + const location = document.location.toString(); + + if ( + this.config.pagesToExclude.length > 0 && + this.config.pagesToExclude.some((re) => re.test(location)) + ) { + return false; + } + + if ( + !this.config.pagesToInclude.length || + this.config.pagesToInclude.some((re) => re.test(location)) + ) { + return true; + } + } + + private getUserDetails(): UserDetails { + return { + userId: this.sessionManager.getUserId(), + sessionId: this.sessionManager.getSession().sessionId + }; + } +} diff --git a/src/event-cache/__mocks__/event-cache.ts b/src/event-cache/__mocks__/event-cache.ts new file mode 100644 index 00000000..2c6ba979 --- /dev/null +++ b/src/event-cache/__mocks__/event-cache.ts @@ -0,0 +1,5 @@ +import { EventCache } from '../event-cache'; + +// TODO: mock whatever we need. + +module.exports = EventCache; diff --git a/src/event-cache/__tests__/EventCache.integ.test.ts b/src/event-cache/__tests__/EventCache.integ.test.ts new file mode 100644 index 00000000..e7043b2b --- /dev/null +++ b/src/event-cache/__tests__/EventCache.integ.test.ts @@ -0,0 +1,65 @@ +import { EventCache } from '../EventCache'; +import { advanceTo } from 'jest-date-mock'; +import * as Utils from '../../test-utils/test-utils'; +import { defaultConfig } from '../../orchestration/Orchestration'; +import { Event } from '../../dispatch/dataplane'; + +describe('EventCache tests', () => { + beforeAll(() => { + advanceTo(0); + }); + + test('when a session expires then a new session is created', async () => { + // Init + const EVENT1_SCHEMA = 'com.amazon.rum.event1'; + const config = { + ...defaultConfig, + ...{ + allowCookies: false, + sessionLengthSeconds: 0 + } + }; + + const eventCache: EventCache = Utils.createEventCache(config); + + // Run + eventCache.recordEvent(EVENT1_SCHEMA, {}); + advanceTo(1); + eventCache.recordEvent(EVENT1_SCHEMA, {}); + + // Assert + expect(eventCache.getEventBatch().events.length).toEqual(6); + }); + + test('meta data contains domain, user agent and page ID', async () => { + // Init + const EVENT1_SCHEMA = 'com.amazon.rum.event1'; + const config = { + ...defaultConfig, + ...{ + allowCookies: false, + sessionLengthSeconds: 0 + } + }; + + const eventCache: EventCache = Utils.createEventCache(config); + const expectedMetaData = { + version: '1.0.0', + domain: 'us-east-1.console.aws.amazon.com', + browserLanguage: 'en-US', + browserName: 'WebKit', + deviceType: 'desktop', + platformType: 'web', + pageId: '/console/home' + }; + + // Run + eventCache.recordEvent(EVENT1_SCHEMA, {}); + + // Assert + const events: Event[] = await eventCache.getEventBatch().events; + events.forEach((event) => { + expect(JSON.parse(event.metadata)).toMatchObject(expectedMetaData); + }); + }); +}); diff --git a/src/event-cache/__tests__/EventCache.test.ts b/src/event-cache/__tests__/EventCache.test.ts new file mode 100644 index 00000000..cb3c3284 --- /dev/null +++ b/src/event-cache/__tests__/EventCache.test.ts @@ -0,0 +1,378 @@ +import { EventCache } from '../EventCache'; +import { advanceTo } from 'jest-date-mock'; +import * as Utils from '../../test-utils/test-utils'; +import { defaultConfig } from '../../orchestration/Orchestration'; +import { SessionManager } from '../../sessions/SessionManager'; +import { EventBatch, Event } from '../../dispatch/dataplane'; + +const getSession = jest.fn(() => ({ + sessionId: 'a', + record: true, + eventCount: 1 +})); +const getUserId = jest.fn(() => 'b'); +const getAttributes = jest.fn(() => {}); +const incrementSessionEventCount = jest.fn(); +jest.mock('../../sessions/SessionManager', () => ({ + SessionManager: jest.fn().mockImplementation(() => ({ + getSession, + getUserId, + getAttributes, + incrementSessionEventCount + })) +})); + +describe('EventCache tests', () => { + beforeAll(() => { + advanceTo(0); + }); + + beforeEach(() => { + getSession.mockClear(); + getUserId.mockClear(); + incrementSessionEventCount.mockClear(); + }); + + test('record does nothing when cache is disabled', async () => { + // Init + const EVENT1_SCHEMA = 'com.amazon.rum.event1'; + const eventCache: EventCache = Utils.createDefaultEventCache(); + + // Run + eventCache.getEventBatch(); + eventCache.disable(); + eventCache.recordEvent(EVENT1_SCHEMA, {}); + + // Assert + expect(eventCache.hasEvents()).toBeFalsy(); + }); + + test('meta data and events are recorded when cache is disabled then enabled', async () => { + // Init + const EVENT1_SCHEMA = 'com.amazon.rum.event1'; + const eventCache: EventCache = Utils.createDefaultEventCache(); + + // Run + eventCache.disable(); + eventCache.enable(); + eventCache.recordEvent(EVENT1_SCHEMA, {}); + + // Assert + expect(eventCache.hasEvents()).toBeTruthy(); + }); + + test('getEventBatch deletes events', async () => { + // Init + const EVENT1_SCHEMA = 'com.amazon.rum.event1'; + const EVENT2_SCHEMA = 'com.amazon.rum.event2'; + const eventCache: EventCache = Utils.createDefaultEventCache(); + + // Run + eventCache.recordEvent(EVENT1_SCHEMA, {}); + eventCache.recordEvent(EVENT2_SCHEMA, {}); + + // Assert + expect(eventCache.hasEvents()).toBeTruthy(); + eventCache.getEventBatch(); + expect(eventCache.hasEvents()).toBeFalsy(); + }); + + test('recordEvent appends events', async () => { + // Init + const EVENT1_SCHEMA = 'com.amazon.rum.event1'; + const EVENT2_SCHEMA = 'com.amazon.rum.event2'; + const eventCache: EventCache = Utils.createDefaultEventCache(); + const expectedEvents: Event[] = [ + { + id: expect.stringMatching(/[0-9a-f\-]+/), + timestamp: new Date(), + type: EVENT1_SCHEMA, + metadata: '{"version":"1.0.0"}', + details: '{}' + }, + { + id: expect.stringMatching(/[0-9a-f\-]+/), + timestamp: new Date(), + type: EVENT2_SCHEMA, + metadata: '{"version":"1.0.0"}', + details: '{}' + } + ]; + + // Run + eventCache.recordEvent(EVENT1_SCHEMA, {}); + eventCache.recordEvent(EVENT2_SCHEMA, {}); + const eventBatch: EventBatch = eventCache.getEventBatch(); + + // Assert + expect(eventBatch.events).toEqual( + expect.arrayContaining(expectedEvents) + ); + }); + + test('getEventBatch limits number of events to batchLimit', async () => { + // Init + const EVENT1_SCHEMA = 'com.amazon.rum.event1'; + const EVENT2_SCHEMA = 'com.amazon.rum.event2'; + const BATCH_LIMIT = 1; + const eventCache: EventCache = Utils.createEventCache({ + ...defaultConfig, + ...{ batchLimit: BATCH_LIMIT } + }); + + // Run + eventCache.recordEvent(EVENT1_SCHEMA, {}); + eventCache.recordEvent(EVENT2_SCHEMA, {}); + + // Assert + // @ts-ignore + expect(eventCache.getEventBatch().events.length).toEqual(BATCH_LIMIT); + // @ts-ignore + expect(eventCache.getEventBatch().events.length).toEqual(BATCH_LIMIT); + // @ts-ignore + expect(eventCache.getEventBatch().events.length).toEqual(0); + }); + + test('getEventBatch returns events in FIFO order', async () => { + // Init + const EVENT1_SCHEMA = 'com.amazon.rum.event1'; + const EVENT2_SCHEMA = 'com.amazon.rum.event2'; + const BATCH_LIMIT = 1; + const eventCache: EventCache = Utils.createEventCache({ + ...defaultConfig, + ...{ batchLimit: BATCH_LIMIT } + }); + + // Run + eventCache.recordEvent(EVENT1_SCHEMA, {}); + eventCache.recordEvent(EVENT2_SCHEMA, {}); + + // Assert + // @ts-ignore + expect(eventCache.getEventBatch().events[0].type).toEqual( + EVENT1_SCHEMA + ); + // @ts-ignore + expect(eventCache.getEventBatch().events[0].type).toEqual( + EVENT2_SCHEMA + ); + }); + + test('when cache size reached, recordEvent drops oldest event', async () => { + // Init + const EVENT1_SCHEMA = 'com.amazon.rum.event1'; + const EVENT2_SCHEMA = 'com.amazon.rum.event2'; + const BATCH_LIMIT = 20; + const EVENT_LIMIT = 2; + const eventCache: EventCache = Utils.createEventCache({ + ...defaultConfig, + ...{ + batchLimit: BATCH_LIMIT, + eventCacheSize: EVENT_LIMIT + } + }); + const expectedEvents: Event[] = [ + { + id: expect.stringMatching(/[0-9a-f\-]+/), + timestamp: new Date(), + type: EVENT2_SCHEMA, + metadata: '{"version":"1.0.0"}', + details: '{}' + } + ]; + + // Run + eventCache.recordEvent(EVENT1_SCHEMA, {}); + eventCache.recordEvent(EVENT2_SCHEMA, {}); + + // Assert + expect((await eventCache.getEventBatch()).events).toEqual( + expect.arrayContaining(expectedEvents) + ); + expect(eventCache.hasEvents()).toBeFalsy(); + }); + + test('when page is denied, recordEvent does not record the event', async () => { + // Init + const EVENT1_SCHEMA = 'com.amazon.rum.event1'; + const eventCache: EventCache = Utils.createEventCache({ + ...defaultConfig, + ...{ + pagesToExclude: [/.*/] + } + }); + + // Run + eventCache.recordEvent(EVENT1_SCHEMA, {}); + + // Assert + expect(eventCache.hasEvents()).toBeFalsy(); + }); + + test('when page is allowed, recordEvent records the event', async () => { + // Init + const EVENT1_SCHEMA = 'com.amazon.rum.event1'; + const eventCache: EventCache = Utils.createEventCache({ + ...defaultConfig, + ...{ + pagesToInclude: [/.*/] + } + }); + const expectedEvents: Event[] = [ + { + id: expect.stringMatching(/[0-9a-f\-]+/), + timestamp: new Date(), + type: EVENT1_SCHEMA, + metadata: '{"version":"1.0.0"}', + details: '{}' + } + ]; + + // Run + eventCache.recordEvent(EVENT1_SCHEMA, {}); + + // Assert + expect((await eventCache.getEventBatch()).events).toEqual( + expect.arrayContaining(expectedEvents) + ); + }); + + test('when page matches both allowed and denied, recordEvent does not record the event', async () => { + // Init + const EVENT1_SCHEMA = 'com.amazon.rum.event1'; + const eventCache: EventCache = Utils.createEventCache({ + ...defaultConfig, + ...{ + pagesToInclude: [/.*/], + pagesToExclude: [/.*/] + } + }); + + // Run + eventCache.recordEvent(EVENT1_SCHEMA, {}); + + // Assert + expect(eventCache.hasEvents()).toBeFalsy(); + }); + + test('when session.record is false then event is not recorded', async () => { + // Init + const getSession = jest.fn(() => ({ sessionId: 'a', record: true })); + const getUserId = jest.fn(() => 'b'); + const incrementSessionEventCount = jest.fn(); + // @ts-ignore + SessionManager.mockImplementation(() => ({ + getSession, + getUserId, + incrementSessionEventCount + })); + + const EVENT1_SCHEMA = 'com.amazon.rum.event1'; + const eventCache: EventCache = Utils.createDefaultEventCache(); + + // Run + eventCache.getEventBatch(); + eventCache.recordEvent(EVENT1_SCHEMA, {}); + + // Assert + expect(eventCache.hasEvents()).toBeFalsy(); + }); + + test('when session.record is true then event is recorded', async () => { + // Init + const getSession = jest.fn(() => ({ + sessionId: 'a', + record: true, + eventCount: 1 + })); + const getUserId = jest.fn(() => 'b'); + const getAttributes = jest.fn(() => {}); + const incrementSessionEventCount = jest.fn(); + // @ts-ignore + SessionManager.mockImplementation(() => ({ + getSession, + getUserId, + getAttributes, + incrementSessionEventCount + })); + + const EVENT1_SCHEMA = 'com.amazon.rum.event1'; + const eventCache: EventCache = Utils.createDefaultEventCache(); + + // Run + eventCache.getEventBatch(); + eventCache.recordEvent(EVENT1_SCHEMA, {}); + + // Assert + expect(eventCache.hasEvents()).toBeTruthy(); + }); + + test('when event limit is reached then recordEvent does not record events', async () => { + // Init + let eventCount = 0; + const getSession = jest.fn().mockImplementation(() => { + eventCount++; + return { + sessionId: 'a', + record: true, + eventCount: eventCount - 1 + }; + }); + const getUserId = jest.fn(() => 'b'); + const getAttributes = jest.fn(() => {}); + const incrementSessionEventCount = jest.fn(); + // @ts-ignore + SessionManager.mockImplementation(() => ({ + getSession, + getUserId, + getAttributes, + incrementSessionEventCount + })); + const EVENT1_SCHEMA = 'com.amazon.rum.event1'; + const config = { + ...defaultConfig, + ...{ + sessionEventLimit: 1 + } + }; + const eventCache: EventCache = Utils.createEventCache(config); + + // Run + eventCache.recordEvent(EVENT1_SCHEMA, {}); + eventCache.recordEvent(EVENT1_SCHEMA, {}); + eventCache.recordEvent(EVENT1_SCHEMA, {}); + + // Assert + expect(eventCache.getEventBatch().events.length).toEqual(1); + }); + + test('when event limit is zero then recordEvent records all events', async () => { + // Init + let eventCount = 0; + const getSession = jest.fn(() => ({ sessionId: 'a', record: true })); + const getUserId = jest.fn(() => 'b'); + const getAttributes = jest.fn(() => {}); + const incrementSessionEventCount = jest.fn(); + // @ts-ignore + SessionManager.mockImplementation(() => ({ + getSession, + getUserId, + getAttributes, + incrementSessionEventCount + })); + const EVENT1_SCHEMA = 'com.amazon.rum.event1'; + const config = { + ...defaultConfig, + ...{ + sessionEventLimit: 0 + } + }; + const eventCache: EventCache = Utils.createEventCache(config); + + // Run + eventCache.recordEvent(EVENT1_SCHEMA, {}); + + // Assert + expect(eventCache.getEventBatch().events.length).toEqual(1); + }); +}); diff --git a/src/event-schemas/cumulative-layout-shift-event.json b/src/event-schemas/cumulative-layout-shift-event.json new file mode 100644 index 00000000..900c20e2 --- /dev/null +++ b/src/event-schemas/cumulative-layout-shift-event.json @@ -0,0 +1,19 @@ +{ + "$id": "com.amazon.rum.cumulative_layout_shift_event", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "CumulativeLayoutShiftEvent", + "type": "object", + "properties": { + "version": { + "const": "1.0.0", + "type": "string", + "description": "Schema version." + }, + "value": { + "type": "number", + "description": "Value of the cls metric" + } + }, + "additionalProperties": false, + "required": ["version", "value"] +} diff --git a/src/event-schemas/dom-event.json b/src/event-schemas/dom-event.json new file mode 100644 index 00000000..2a0c0f09 --- /dev/null +++ b/src/event-schemas/dom-event.json @@ -0,0 +1,23 @@ +{ + "$id": "com.amazon.rum.dom_event", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "DomEvent", + "type": "object", + "properties": { + "version": { + "const": "1.0.0", + "type": "string", + "description": "Schema version." + }, + "event": { + "type": "string", + "description": "DOM event type (e.g., click, scroll, hover, etc.)" + }, + "elementId": { + "type": "string", + "description": "DOM element ID." + } + }, + "additionalProperties": false, + "required": ["version", "event", "elementId"] +} diff --git a/src/event-schemas/first-input-delay-event.json b/src/event-schemas/first-input-delay-event.json new file mode 100644 index 00000000..59afcd3f --- /dev/null +++ b/src/event-schemas/first-input-delay-event.json @@ -0,0 +1,19 @@ +{ + "$id": "com.amazon.rum.first_input_delay_event", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "FirstInputDelayEvent", + "type": "object", + "properties": { + "version": { + "const": "1.0.0", + "type": "string", + "description": "Schema version." + }, + "value": { + "type": "number", + "description": "Value of the fid metric" + } + }, + "additionalProperties": false, + "required": ["version", "value"] +} diff --git a/src/event-schemas/http-event.json b/src/event-schemas/http-event.json new file mode 100644 index 00000000..2b11aeb7 --- /dev/null +++ b/src/event-schemas/http-event.json @@ -0,0 +1,58 @@ +{ + "$id": "com.amazon.rum.http_event", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "HttpEvent", + "type": "object", + "properties": { + "version": { + "const": "1.0.0", + "type": "string", + "description": "Schema version." + }, + "request": { + "type": "object", + "properties": { + "method": { "type": "string" }, + "url": { "type": "string" } + }, + "additionalProperties": false, + "required": ["method", "url"] + }, + "response": { + "type": "object", + "properties": { + "status": { "type": "number" }, + "statusText": { "type": "string" } + }, + "additionalProperties": false, + "required": ["status"] + }, + "error": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Error type (eg., TypeError, ParseError, etc)." + }, + "message": { + "type": "string" + }, + "filename": { + "type": "string" + }, + "lineno": { + "type": "number" + }, + "colno": { + "type": "number" + }, + "stack": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false, + "required": ["version", "request"] +} diff --git a/src/event-schemas/js-error-event.json b/src/event-schemas/js-error-event.json new file mode 100644 index 00000000..f384424d --- /dev/null +++ b/src/event-schemas/js-error-event.json @@ -0,0 +1,34 @@ +{ + "$id": "com.amazon.rum.js_error_event", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "JSErrorEvent", + "type": "object", + "properties": { + "version": { + "const": "1.0.0", + "type": "string", + "description": "Schema version." + }, + "type": { + "type": "string", + "description": "Error type (eg., TypeError, ParseError, etc)." + }, + "message": { + "type": "string" + }, + "filename": { + "type": "string" + }, + "lineno": { + "type": "number" + }, + "colno": { + "type": "number" + }, + "stack": { + "type": "string" + } + }, + "additionalProperties": false, + "required": ["version"] +} diff --git a/src/event-schemas/largest-contentful-paint-event.json b/src/event-schemas/largest-contentful-paint-event.json new file mode 100644 index 00000000..e3fda0fd --- /dev/null +++ b/src/event-schemas/largest-contentful-paint-event.json @@ -0,0 +1,19 @@ +{ + "$id": "com.amazon.rum.largest_contentful_paint_event", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "LargestContentfulPaintEvent", + "type": "object", + "properties": { + "version": { + "const": "1.0.0", + "type": "string", + "description": "Schema version." + }, + "value": { + "type": "number", + "description": "Value of the lcp metric" + } + }, + "additionalProperties": false, + "required": ["version", "value"] +} diff --git a/src/event-schemas/meta-data.json b/src/event-schemas/meta-data.json new file mode 100644 index 00000000..e766897c --- /dev/null +++ b/src/event-schemas/meta-data.json @@ -0,0 +1,69 @@ +{ + "$id": "com.amazon.rum.meta_data", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "MetaData", + "type": "object", + "properties": { + "version": { + "const": "1.0.0", + "type": "string", + "description": "Schema version." + }, + "browserLanguage": { + "type": "string" + }, + "browserName": { + "type": "string" + }, + "browserVersion": { + "type": "string" + }, + "osName": { + "type": "string" + }, + "osVersion": { + "type": "string" + }, + "deviceType": { + "type": "string" + }, + "platformType": { + "type": "string" + }, + "pageUrl": { + "type": "string" + }, + "url": { + "type": "string" + }, + "pageId": { + "type": "string" + }, + "parentPageId": { + "type": "string" + }, + "interaction": { + "type": "number" + }, + "referrerUrl": { + "type": "string" + }, + "pageTitle": { + "type": "string" + }, + "title": { + "type": "string" + }, + "countryCode": { + "type": "string" + }, + "subdivisionCode": { + "type": "string" + }, + "domain": { + "type": "string" + } + }, + "additionalProperties": false, + "required": ["version", "domain"] +} diff --git a/src/event-schemas/navigation-event.json b/src/event-schemas/navigation-event.json new file mode 100644 index 00000000..7f608bfb --- /dev/null +++ b/src/event-schemas/navigation-event.json @@ -0,0 +1,152 @@ +{ + "$id": "com.amazon.rum.performance_navigation_event", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "NavigationEvent", + "type": "object", + "properties": { + "version": { + "const": "1.0.0", + "type": "string", + "description": "Schema version." + }, + "targetUrl": { + "description": "Page URL", + "type": "string" + }, + "initiatorType": { + "type": "string", + "enum": ["navigation"] + }, + "navigationType": { + "description": "An unsigned short which indicates how the navigation to this page was done. Possible values are:TYPE_NAVIGATE (0), TYPE_RELOAD (1), TYPE_BACK_FORWARD (2), TYPE_RESERVED (255)", + "type": "string", + "enum": ["navigate", "reload", "back_forward", "reserved"] + }, + "startTime": { + "type": "number" + }, + "unloadEventStart": { + "type": "number" + }, + "promptForUnload": { + "type": "number" + }, + "redirectCount": { + "type": "integer" + }, + "redirectStart": { + "type": "number" + }, + "redirectTime": { + "type": "number" + }, + "workerStart": { + "type": "number" + }, + "workerTime": { + "type": "number" + }, + "fetchStart": { + "type": "number" + }, + "domainLookupStart": { + "type": "number" + }, + "dns": { + "type": "number" + }, + "nextHopProtocol": { + "type": "string" + }, + "connectStart": { + "type": "number" + }, + "connect": { + "type": "number" + }, + "secureConnectionStart": { + "type": "number" + }, + "tlsTime": { + "type": "number" + }, + "requestStart": { + "type": "number" + }, + "timeToFirstByte": { + "type": "number" + }, + "responseStart": { + "type": "number" + }, + "responseTime": { + "type": "number" + }, + "domInteractive": { + "type": "number" + }, + "domContentLoadedEventStart": { + "type": "number" + }, + "domContentLoaded": { + "type": "number" + }, + "domComplete": { + "type": "number" + }, + "domProcessingTime": { + "type": "number" + }, + "loadEventStart": { + "type": "number" + }, + "loadEventTime": { + "type": "number" + }, + "duration": { + "type": "number" + }, + "headerSize": { + "type": "number" + }, + "transferSize": { + "type": "number" + }, + "compressionRatio": { + "type": "number" + }, + "navigationTimingLevel": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "version", + "initiatorType", + "startTime", + "unloadEventStart", + "promptForUnload", + "redirectStart", + "redirectTime", + "fetchStart", + "domainLookupStart", + "dns", + "connectStart", + "connect", + "secureConnectionStart", + "tlsTime", + "requestStart", + "timeToFirstByte", + "responseStart", + "responseTime", + "domInteractive", + "domContentLoadedEventStart", + "domContentLoaded", + "domComplete", + "domProcessingTime", + "loadEventStart", + "loadEventTime", + "duration", + "navigationTimingLevel" + ] +} diff --git a/src/event-schemas/page-close-event.json b/src/event-schemas/page-close-event.json new file mode 100644 index 00000000..e80f65f7 --- /dev/null +++ b/src/event-schemas/page-close-event.json @@ -0,0 +1,19 @@ +{ + "$id": "com.amazon.rum.page_close_event", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Page Close Event", + "type": "object", + "properties": { + "version": { + "const": "1.0.0", + "type": "string", + "description": "Schema version." + }, + "pageId": { "type": "string" }, + "pageInteractionId": { "type": "string" }, + "interaction": { "type": "number" }, + "duration": { "type": "number" } + }, + "additionalProperties": false, + "required": ["pageId", "pageInteractionId", "interaction"] +} diff --git a/src/event-schemas/page-view-event.json b/src/event-schemas/page-view-event.json new file mode 100644 index 00000000..60bd02b8 --- /dev/null +++ b/src/event-schemas/page-view-event.json @@ -0,0 +1,19 @@ +{ + "$id": "com.amazon.rum.page_view_event", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Page View Event", + "type": "object", + "properties": { + "version": { + "const": "1.0.0", + "type": "string", + "description": "Schema version." + }, + "pageId": { "type": "string" }, + "pageInteractionId": { "type": "string" }, + "interaction": { "type": "number" }, + "parentPageInteractionId": { "type": "string" } + }, + "additionalProperties": false, + "required": ["pageId"] +} diff --git a/src/event-schemas/paint-event.json b/src/event-schemas/paint-event.json new file mode 100644 index 00000000..4181ff78 --- /dev/null +++ b/src/event-schemas/paint-event.json @@ -0,0 +1,23 @@ +{ + "$id": "com.amazon.rum.performance_paint_event", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "PaintEvent", + "type": "object", + "properties": { + "version": { + "const": "1.0.0", + "type": "string", + "description": "Schema version." + }, + "startTime": { + "type": "number", + "description": "Beginning of the event in milliseconds" + }, + "duration": { + "type": "number", + "description": "Duration of the event in milliseconds" + } + }, + "additionalProperties": false, + "required": ["version", "startTime", "duration"] +} diff --git a/src/event-schemas/resource-event.json b/src/event-schemas/resource-event.json new file mode 100644 index 00000000..4c9bd399 --- /dev/null +++ b/src/event-schemas/resource-event.json @@ -0,0 +1,113 @@ +{ + "$id": "com.amazon.rum.performance_resource_event", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "ResourceEvent", + "type": "object", + "properties": { + "version": { + "const": "1.0.0", + "type": "string", + "description": "Schema version." + }, + "targetUrl": { + "description": "Page URL", + "type": "string" + }, + "initiatorType": { + "type": "string" + }, + "startTime": { + "type": "number" + }, + "redirectStart": { + "type": "number" + }, + "redirectTime": { + "type": "number" + }, + "workerStart": { + "type": "number" + }, + "workerTime": { + "type": "number" + }, + "fetchStart": { + "type": "number" + }, + "domainLookupStart": { + "type": "number" + }, + "dns": { + "type": "number" + }, + "nextHopProtocol": { + "type": "string" + }, + "connectStart": { + "type": "number" + }, + "connect": { + "type": "number" + }, + "secureConnectionStart": { + "type": "number" + }, + "tlsTime": { + "type": "number" + }, + "requestStart": { + "type": "number" + }, + "timeToFirstByte": { + "type": "number" + }, + "responseStart": { + "type": "number" + }, + "responseTime": { + "type": "number" + }, + "duration": { + "type": "number" + }, + "headerSize": { + "type": "number" + }, + "transferSize": { + "type": "number" + }, + "compressionRatio": { + "type": "number" + }, + "fileType": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "version", + "targetUrl", + "initiatorType", + "startTime", + "redirectStart", + "redirectTime", + "workerStart", + "workerTime", + "fetchStart", + "domainLookupStart", + "dns", + "nextHopProtocol", + "connectStart", + "connect", + "secureConnectionStart", + "tlsTime", + "requestStart", + "timeToFirstByte", + "responseStart", + "responseTime", + "duration", + "headerSize", + "compressionRatio", + "fileType" + ] +} diff --git a/src/event-schemas/session-start-event.json b/src/event-schemas/session-start-event.json new file mode 100644 index 00000000..8c21a886 --- /dev/null +++ b/src/event-schemas/session-start-event.json @@ -0,0 +1,15 @@ +{ + "$id": "com.amazon.rum.session_start_event", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "SessionStartEvent", + "type": "object", + "properties": { + "version": { + "const": "1.0.0", + "type": "string", + "description": "Schema version." + } + }, + "additionalProperties": false, + "required": ["version"] +} diff --git a/src/event-schemas/xray-trace-event.json b/src/event-schemas/xray-trace-event.json new file mode 100644 index 00000000..104342e9 --- /dev/null +++ b/src/event-schemas/xray-trace-event.json @@ -0,0 +1,159 @@ +{ + "$id": "com.amazon.xray_trace_event", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "X-Ray Trace Event", + "type": "object", + + "definitions": { + "stackFrame": { + "$id": "#stackFrame", + "type": "object", + "properties": { + "class_name": { + "type": "string" + }, + "file_name": { + "type": "string" + }, + "line": { + "type": "integer" + }, + "method_name": { + "type": "string" + } + }, + "additionalProperties": false + }, + + "exception": { + "$id": "#exception", + "type": "object", + "properties": { + "id": { "type": "string" }, + "message": { "type": "string" }, + "type": { "type": "string" }, + "remote": { "type": "boolean" }, + "truncated": { "type": "integer" }, + "cause": { "type": "string" }, + "stack": { + "type": "array", + "items": { + "$ref": "#/definitions/stackFrame" + } + } + }, + "additionalProperties": false + }, + + "cause": { + "$id": "#cause", + "type": "object", + "properties": { + "exceptions": { + "type": "array", + "items": { + "$ref": "#/definitions/exception" + } + } + }, + "additionalProperties": false + }, + "annotations": { + "$id": "#annotations", + "type": "object", + "additionalProperties": true + }, + "metadata": { + "$id": "#metadata", + "type": "object", + "additionalProperties": true + }, + + "http": { + "$id": "#http", + "type": "object", + "properties": { + "request": { + "type": "object", + "properties": { + "method": { "type": "string" }, + "url": { "type": "string" }, + "client_ip": { "type": "string" }, + "x_forwarded_for": { "type": "boolean" }, + "traced": { "type": "boolean" } + }, + "additionalProperties": false + }, + "response": { + "type": "object", + "properties": { + "status": { "type": "number" }, + "content_length": { "type": "number" } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + + "subsegment": { + "$id": "#subsegment", + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "start_time": { "type": "number" }, + "end_time": { "type": "number" }, + "origin": { "type": "string" }, + "in_progress": { "type": "boolean" }, + "trace_id": { "type": "string" }, + "parent_id": { "type": "string" }, + "type": { "type": "string", "value": "subsegment" }, + "http": { "$ref": "#/definitions/http" }, + "error": { "type": "boolean" }, + "throttle": { "type": "boolean" }, + "fault": { "type": "boolean" }, + "cause": { "$ref": "#/definitions/cause" }, + "annotations": { "$ref": "#/definitions/annotations" }, + "metadata": { "$ref": "#/definitions/metadata" }, + "subsegments": { + "type": "array", + "items": { "$ref": "#/definitions/subsegment" } + } + }, + "additionalProperties": false, + "required": ["id", "name", "start_time"] + } + }, + + "properties": { + "version": { + "const": "1.0.0", + "type": "string" + }, + "name": { "type": "string" }, + "id": { "type": "string" }, + "start_time": { "type": "number" }, + "trace_id": { "type": "string" }, + "end_time": { "type": "number" }, + "origin": { "type": "string" }, + "in_progress": { "type": "boolean" }, + "user": { "type": "string" }, + "parent_id": { "type": "string" }, + "http": { "$ref": "#/definitions/http" }, + "error": { "type": "boolean" }, + "throttle": { "type": "boolean" }, + "fault": { "type": "boolean" }, + "cause": { "$ref": "#/definitions/cause" }, + "annotations": { "$ref": "#/definitions/annotations" }, + "metadata": { "$ref": "#/definitions/metadata" }, + "subsegments": { + "type": "array", + "items": { + "$ref": "#/definitions/subsegment" + } + } + }, + "additionalProperties": false, + "required": ["name", "id", "trace_id", "start_time"] +} diff --git a/src/index-browser.ts b/src/index-browser.ts new file mode 100644 index 00000000..58afe7a7 --- /dev/null +++ b/src/index-browser.ts @@ -0,0 +1,8 @@ +import { AwsRumClientInit, CommandQueue } from './CommandQueue'; +declare global { + interface Window { + AwsRumClient: AwsRumClientInit; + } +} +// tslint:disable:no-unused-expression +new CommandQueue(window.AwsRumClient); diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 00000000..abf23c9e --- /dev/null +++ b/src/index.ts @@ -0,0 +1,13 @@ +export { + PartialConfig as AwsRumConfig, + Orchestration as AwsRum +} from './orchestration/Orchestration'; +export * from './plugins/event-plugins/DomEventPlugin'; +export * from './plugins/event-plugins/JsErrorPlugin'; +export * from './plugins/event-plugins/NavigationPlugin'; +export * from './plugins/event-plugins/PageViewPlugin'; +export * from './plugins/event-plugins/PaintPlugin'; +export * from './plugins/event-plugins/ResourcePlugin'; +export * from './plugins/event-plugins/WebVitalsPlugin'; +export * from './plugins/event-plugins/FetchPlugin'; +export * from './plugins/event-plugins/XhrPlugin'; diff --git a/src/loader/loader-cookies-disabled.js b/src/loader/loader-cookies-disabled.js new file mode 100644 index 00000000..d0080442 --- /dev/null +++ b/src/loader/loader-cookies-disabled.js @@ -0,0 +1,23 @@ +import { loader } from './loader'; +import { showRequestClientBuilder } from '../test-utils/mock-http-handler'; +loader( + 'cwr', + 'abc123', + 'appname', + '1.0', + 'us-west-2', + './rum_javascript_telemetry.js', + { + userIdRetentionDays: 1, + dispatchInterval: 0, + allowCookies: false, + eventPluginsToLoad: [], + telemetries: [], + clientBuilder: showRequestClientBuilder + } +); +window.cwr('setAwsCredentials', { + accessKeyId: 'a', + secretAccessKey: 'b', + sessionToken: 'c' +}); diff --git a/src/loader/loader-cookies-enabled.js b/src/loader/loader-cookies-enabled.js new file mode 100644 index 00000000..ea86a08a --- /dev/null +++ b/src/loader/loader-cookies-enabled.js @@ -0,0 +1,22 @@ +import { loader } from './loader'; +import { showRequestClientBuilder } from '../test-utils/mock-http-handler'; +loader( + 'cwr', + 'abc123', + 'appname', + '1.0', + 'us-west-2', + './rum_javascript_telemetry.js', + { + dispatchInterval: 0, + allowCookies: true, + eventPluginsToLoad: [], + telemetries: [], + clientBuilder: showRequestClientBuilder + } +); +window.cwr('setAwsCredentials', { + accessKeyId: 'a', + secretAccessKey: 'b', + sessionToken: 'c' +}); diff --git a/src/loader/loader-dom-event.js b/src/loader/loader-dom-event.js new file mode 100644 index 00000000..192e6f43 --- /dev/null +++ b/src/loader/loader-dom-event.js @@ -0,0 +1,24 @@ +import { loader } from './loader'; +import { showRequestClientBuilder } from '../test-utils/mock-http-handler'; +import { DomEventPlugin } from '../plugins/event-plugins/DomEventPlugin'; +loader( + 'cwr', + 'abc123', + 'appname', + '1.0', + 'us-west-2', + './rum_javascript_telemetry.js', + { + allowCookies: true, + dispatchInterval: 0, + metaDataPluginsToLoad: [], + eventPluginsToLoad: [new DomEventPlugin()], + telemetries: [], + clientBuilder: showRequestClientBuilder + } +); +window.cwr('setAwsCredentials', { + accessKeyId: 'a', + secretAccessKey: 'b', + sessionToken: 'c' +}); diff --git a/src/loader/loader-http-fetch-event.js b/src/loader/loader-http-fetch-event.js new file mode 100644 index 00000000..67e19fc7 --- /dev/null +++ b/src/loader/loader-http-fetch-event.js @@ -0,0 +1,35 @@ +import { loader } from './loader'; +import { showRequestClientBuilder } from '../test-utils/mock-http-handler'; +import { FetchPlugin } from '../plugins/event-plugins/FetchPlugin'; +import { defaultConfig } from '../plugins/utils/http-utils'; + +const config = { + ...defaultConfig, + ...{ + logicalServiceName: 'sample.rum.aws.amazon.com', + trace: true, + recordAllRequests: true + } +}; + +loader( + 'cwr', + 'abc123', + 'appname', + '1.0', + 'us-west-2', + './rum_javascript_telemetry.js', + { + allowCookies: true, + dispatchInterval: 0, + metaDataPluginsToLoad: [], + eventPluginsToLoad: [new FetchPlugin(config)], + telemetries: [], + clientBuilder: showRequestClientBuilder + } +); +window.cwr('setAwsCredentials', { + accessKeyId: 'a', + secretAccessKey: 'b', + sessionToken: 'c' +}); diff --git a/src/loader/loader-http-xhr-event.js b/src/loader/loader-http-xhr-event.js new file mode 100644 index 00000000..17b6261d --- /dev/null +++ b/src/loader/loader-http-xhr-event.js @@ -0,0 +1,36 @@ +import { loader } from './loader'; +import { showRequestClientBuilder } from '../test-utils/mock-http-handler'; +import { XhrPlugin } from '../plugins/event-plugins/XhrPlugin'; +import { defaultConfig } from '../plugins/utils/http-utils'; + +const config = { + ...defaultConfig, + ...{ + logicalServiceName: 'sample.rum.aws.amazon.com', + urlsToInclude: [/response\.json/], + trace: true, + recordAllRequests: true + } +}; + +loader( + 'cwr', + 'abc123', + 'appname', + '1.0', + 'us-west-2', + './rum_javascript_telemetry.js', + { + allowCookies: true, + dispatchInterval: 0, + metaDataPluginsToLoad: [], + eventPluginsToLoad: [new XhrPlugin(config)], + telemetries: [], + clientBuilder: showRequestClientBuilder + } +); +window.cwr('setAwsCredentials', { + accessKeyId: 'a', + secretAccessKey: 'b', + sessionToken: 'c' +}); diff --git a/src/loader/loader-js-error-event.js b/src/loader/loader-js-error-event.js new file mode 100644 index 00000000..66cb3c97 --- /dev/null +++ b/src/loader/loader-js-error-event.js @@ -0,0 +1,24 @@ +import { loader } from './loader'; +import { showRequestClientBuilder } from '../test-utils/mock-http-handler'; +import { JsErrorPlugin } from '../plugins/event-plugins/JsErrorPlugin'; +loader( + 'cwr', + 'abc123', + 'appname', + '1.0', + 'us-west-2', + './rum_javascript_telemetry.js', + { + allowCookies: true, + dispatchInterval: 0, + metaDataPluginsToLoad: [], + eventPluginsToLoad: [new JsErrorPlugin()], + telemetries: [], + clientBuilder: showRequestClientBuilder + } +); +window.cwr('setAwsCredentials', { + accessKeyId: 'a', + secretAccessKey: 'b', + sessionToken: 'c' +}); diff --git a/src/loader/loader-page-event.js b/src/loader/loader-page-event.js new file mode 100644 index 00000000..6bb0022c --- /dev/null +++ b/src/loader/loader-page-event.js @@ -0,0 +1,28 @@ +import { loader } from './loader'; +import { showRequestClientBuilder } from '../test-utils/mock-http-handler'; +import { PageViewPlugin } from '../plugins/event-plugins/PageViewPlugin'; +import { defaultConfig } from '../plugins/utils/http-utils'; + +loader( + 'cwr', + 'abc123', + 'appname', + '1.0', + 'us-west-2', + './rum_javascript_telemetry.js', + { + allowCookies: true, + dispatchInterval: 0, + metaDataPluginsToLoad: [], + eventPluginsToLoad: [new PageViewPlugin(defaultConfig)], + telemetries: [], + pagesToInclude: [/\/(page_event.html|page_view_one|page_view_two)/], + pagesToExclude: [/\/page_view_do_not_record/], + clientBuilder: showRequestClientBuilder + } +); +window.cwr('setAwsCredentials', { + accessKeyId: 'a', + secretAccessKey: 'b', + sessionToken: 'c' +}); diff --git a/src/loader/loader-post-load-command-queue-test.js b/src/loader/loader-post-load-command-queue-test.js new file mode 100644 index 00000000..80df32ae --- /dev/null +++ b/src/loader/loader-post-load-command-queue-test.js @@ -0,0 +1,17 @@ +import { loader } from './loader'; +import { showRequestClientBuilder } from '../test-utils/mock-http-handler'; +loader( + 'cwr', + 'abc123', + 'appname', + '1.0', + 'us-west-2', + './rum_javascript_telemetry.js', + { + dispatchInterval: 0, + clientBuilder: showRequestClientBuilder + } +); +setTimeout(() => { + cwr('unsupported_command', {}); +}, 1000); diff --git a/src/loader/loader-pre-load-command-queue-test.js b/src/loader/loader-pre-load-command-queue-test.js new file mode 100644 index 00000000..cc6691bd --- /dev/null +++ b/src/loader/loader-pre-load-command-queue-test.js @@ -0,0 +1,15 @@ +import { loader } from './loader'; +import { showRequestClientBuilder } from '../test-utils/mock-http-handler'; +loader( + 'cwr', + 'abc123', + 'appname', + '1.0', + 'us-west-2', + './rum_javascript_telemetry.js', + { + dispatchInterval: 0, + clientBuilder: showRequestClientBuilder + } +); +cwr('unsupported_command', {}); diff --git a/src/loader/loader-standard.js b/src/loader/loader-standard.js new file mode 100644 index 00000000..4f028531 --- /dev/null +++ b/src/loader/loader-standard.js @@ -0,0 +1,20 @@ +import { loader } from '../loader/loader'; +import { showRequestClientBuilder } from '../test-utils/mock-http-handler'; +loader( + 'cwr', + 'abc123', + 'appname', + '1.0', + 'us-west-2', + './rum_javascript_telemetry.js', + { + allowCookies: true, + dispatchInterval: 0, + clientBuilder: showRequestClientBuilder + } +); +window.cwr('setAwsCredentials', { + accessKeyId: 'a', + secretAccessKey: 'b', + sessionToken: 'c' +}); diff --git a/src/loader/loader-web-vital-event.js b/src/loader/loader-web-vital-event.js new file mode 100644 index 00000000..c107eaf9 --- /dev/null +++ b/src/loader/loader-web-vital-event.js @@ -0,0 +1,23 @@ +import { loader } from './loader'; +import { showRequestClientBuilder } from '../test-utils/mock-http-handler'; +import { WebVitalsPlugin } from '../plugins/event-plugins/WebVitalsPlugin'; +loader( + 'cwr', + 'abc123', + 'appname', + '1.0', + 'us-west-2', + './rum_javascript_telemetry.js', + { + dispatchInterval: 0, + metaDataPluginsToLoad: [], + eventPluginsToLoad: [new WebVitalsPlugin()], + telemetries: [], + clientBuilder: showRequestClientBuilder + } +); +window.cwr('setAwsCredentials', { + accessKeyId: 'a', + secretAccessKey: 'b', + sessionToken: 'c' +}); diff --git a/src/loader/loader.js b/src/loader/loader.js new file mode 100644 index 00000000..a980ec8e --- /dev/null +++ b/src/loader/loader.js @@ -0,0 +1,36 @@ +export function loader( + namespace, + applicationId, + applicationName, + applicationVersion, + region, + clientUri, + config +) { + (function (n, i, a, v, r, s, c, x, z) { + // The global object that the AWS RUM client will use to read configuration and commands. + x = window.AwsRumClient = { q: [], n: n, i: i, a: a, v: v, r: r, c: c }; + + // The AWS RUM client's JavaScript API + window[n] = function (c, p) { + x.q.push({ c: c, p: p }); + }; + + // Asynchronously load the script and ensure execution priority + z = document.createElement('script'); + z.async = true; + z.src = s; + document.head.insertBefore( + z, + document.getElementsByTagName('script')[0] + ); + })( + namespace, + applicationId, + applicationName, + applicationVersion, + region, + clientUri, + config + ); +} diff --git a/src/loader/utils/scorekeep.js b/src/loader/utils/scorekeep.js new file mode 100644 index 00000000..f15a9e30 --- /dev/null +++ b/src/loader/utils/scorekeep.js @@ -0,0 +1,159 @@ +export function randomUserName() { + return `user${Math.floor(Math.random() * 1000)}`; +} +export function randomSessionName() { + return `session${Math.floor(Math.random() * 1000)}`; +} +export function randomGameName() { + return `game${Math.floor(Math.random() * 1000)}`; +} +export function randomGameRules() { + return 'TicTacToe'; +} + +export async function run() { + let session; + let game; + const username = randomUserName(); + const sessionname = randomSessionName(); + const gamename = randomGameName(); + const rules = randomGameRules(); + const user = await createUser(username); + session = await createSession(); + session = await updateSession(session.id, sessionname, username); + game = await createGame(session.id); + game = await updateGame(game.id, game.session, gamename, rules, [user.id]); + await setRules(game.id, game.session); + await startGame(game.id, game.session); + game = await getInitialState(game.id, game.session); + await play(session.id, game.id, user.id, 'X1'); + await play(session.id, game.id, user.id, 'O2'); + await play(session.id, game.id, user.id, 'X3'); + await play(session.id, game.id, user.id, 'O4'); + await play(session.id, game.id, user.id, 'X5'); + await play(session.id, game.id, user.id, 'O6'); + await play(session.id, game.id, user.id, 'X7'); +} + +export async function createUser(username) { + const response = await fetch( + 'http://scorekeep-env.eba-mi3pgqai.us-west-2.elasticbeanstalk.com/api/user', + { + method: 'POST', + headers: { 'Content-Type': 'application/json;charset=utf-8' }, + body: JSON.stringify({ name: username }) + } + ); + // Example response: {"id":"JVTUDFG6","name":"myuser"} + return response.json(); +} + +export async function createSession() { + const response = await fetch( + 'http://scorekeep-env.eba-mi3pgqai.us-west-2.elasticbeanstalk.com/api/session', + { + method: 'POST', + headers: { 'Content-Type': 'application/json;charset=utf-8' }, + body: JSON.stringify({}) + } + ); + // Example response: {"id":"2HM515LD","owner":null,"name":null,"users":null,"games":null} + return response.json(); +} + +export async function updateSession(sessionId, sessionName, ownerId) { + const response = await fetch( + `http://scorekeep-env.eba-mi3pgqai.us-west-2.elasticbeanstalk.com/api/session/${sessionId}`, + { + method: 'PUT', + headers: { 'Content-Type': 'application/json;charset=utf-8' }, + body: JSON.stringify({ + id: sessionId, + owner: ownerId, + name: sessionName, + users: null, + games: null + }) + } + ); + // Example response: {"id":"2HM515LD","owner":"JVTUDFG6","name":"games","users":null,"games":null} + return response.json(); +} + +export async function createGame(sessionId) { + const response = await fetch( + `http://scorekeep-env.eba-mi3pgqai.us-west-2.elasticbeanstalk.com/api/game/${sessionId}`, + { + method: 'POST', + headers: { 'Content-Type': 'application/json;charset=utf-8' }, + body: JSON.stringify({}) + } + ); + // Example response: {"id":"QJ57AQDR","session":"2HM515LD","name":null,"users":null,"rules":null,"startTime":null,"endTime":null,"states":null,"moves":null} + return response.json(); +} + +export async function updateGame(gameId, sessionId, gameName, rules, users) { + const response = await fetch( + `http://scorekeep-env.eba-mi3pgqai.us-west-2.elasticbeanstalk.com/api/game/${sessionId}/${gameId}`, + { + method: 'PUT', + headers: { 'Content-Type': 'application/json;charset=utf-8' }, + body: JSON.stringify({ + id: gameId, + session: sessionId, + name: gameName, + users: users, + rules: rules, + startTime: Date.now() + }) + } + ); + // Example response: {"id":"2HM515LD","owner":"JVTUDFG6","name":"games","users":null,"games":null} + return response.json(); +} + +export async function setRules(gameId, sessionId) { + const response = await fetch( + `http://scorekeep-env.eba-mi3pgqai.us-west-2.elasticbeanstalk.com/api/game/${sessionId}/${gameId}/rules/TicTacToe`, + { + method: 'PUT', + headers: { 'Content-Type': 'application/json;charset=utf-8' } + } + ); +} + +export async function startGame(gameId, sessionId) { + const response = await fetch( + `http://scorekeep-env.eba-mi3pgqai.us-west-2.elasticbeanstalk.com/api/game/${sessionId}/${gameId}/starttime/${Date.now()}`, + { + method: 'PUT', + headers: { 'Content-Type': 'application/json;charset=utf-8' } + } + ); +} + +export async function getInitialState(gameId, sessionId) { + const response = await fetch( + `http://scorekeep-env.eba-mi3pgqai.us-west-2.elasticbeanstalk.com/api/game/${sessionId}/${gameId}`, + { + method: 'GET', + headers: { 'Content-Type': 'application/json;charset=utf-8' } + } + ); + // Example response: {"id":"GC07VRGC","session":"6ROKMJ04","name":"game340","users":["2DTM9BEB"],"rules":"TicTacToe","startTime":1621296353039,"endTime":null,"states":["H6VPUAUU"],"moves":null} + return response.json(); +} + +export async function play(sessionId, gameId, userId, move) { + const response = await fetch( + `http://scorekeep-env.eba-mi3pgqai.us-west-2.elasticbeanstalk.com/api/move/${sessionId}/${gameId}/${userId}`, + { + method: 'POST', + headers: { 'Content-Type': 'application/json;charset=utf-8' }, + body: move + } + ); + // Example response: {"id":"HI2TEC22","game":"MHU803QE","session":"2IA03FM","user":"TECIPULQ","move":"X7"} + return response.json(); +} diff --git a/src/orchestration/Orchestration.ts b/src/orchestration/Orchestration.ts new file mode 100644 index 00000000..7e73ddc9 --- /dev/null +++ b/src/orchestration/Orchestration.ts @@ -0,0 +1,396 @@ +import { Plugin, PluginContext } from '../plugins/Plugin'; +import { Authentication } from '../dispatch/Authentication'; +import { EnhancedAuthentication } from '../dispatch/EnhancedAuthentication'; +import { PluginManager } from '../plugins/PluginManager'; +import { DomEventPlugin } from '../plugins/event-plugins/DomEventPlugin'; +import { JsErrorPlugin } from '../plugins/event-plugins/JsErrorPlugin'; +import { EventCache } from '../event-cache/EventCache'; +import { ClientBuilder, Dispatch } from '../dispatch/Dispatch'; +import { CredentialProvider, Credentials } from '@aws-sdk/types'; +import { NavigationPlugin } from '../plugins/event-plugins/NavigationPlugin'; +import { PaintPlugin } from '../plugins/event-plugins/PaintPlugin'; +import { ResourcePlugin } from '../plugins/event-plugins/ResourcePlugin'; +import { WebVitalsPlugin } from '../plugins/event-plugins/WebVitalsPlugin'; +import { XhrPlugin } from '../plugins/event-plugins/XhrPlugin'; +import { FetchPlugin } from '../plugins/event-plugins/FetchPlugin'; +import { PageViewPlugin } from '../plugins/event-plugins/PageViewPlugin'; + +const DATA_PLANE_REGION_PLACEHOLDER = '[region]'; + +const DATA_PLANE_DEFAULT_ENDPOINT = + 'https://dataplane.[region].gamma.rum.aws.dev'; + +const DEFAULT_DISPATCH_INTERVAL = 5000; + +// Builtin plugin IDs +const JS_ERROR_EVENT_PLUGIN_ID = 'com.amazonaws.rum.js-error'; + +export enum TELEMETRY_TYPES { + ERRORS = 'errors', + PERFORMANCE = 'performance', + JOURNEY = 'journey', + INTERACTION = 'interaction', + HTTP = 'http', + SINGLE_PAGE_APP_VIEWS = 'single-page-app-views' +} + +type PluginInitializer = () => Plugin[]; + +interface DataCollectionFunctor { + [key: string]: PluginInitializer; +} + +export enum PAGE_ID_FORMAT { + PATH = 'PATH', + HASH = 'HASH', + PATH_AND_HASH = 'PATH_AND_HASH' +} + +export type PartialConfig = { + allowCookies?: boolean; + batchLimit?: number; + clientBuilder?: ClientBuilder; + dispatchInterval?: number; + endpoint?: string; + eventCacheSize?: number; + eventPluginsToLoad?: Plugin[]; + guestRoleArn?: string; + identityPoolId?: string; + pageIdFormat?: PAGE_ID_FORMAT; + pagesToExclude?: RegExp[]; + pagesToInclude?: RegExp[]; + sessionEventLimit?: number; + sessionLengthSeconds?: number; + sessionSampleRate?: number; + userIdRetentionDays?: number; + /** + * Application owners think about data collection in terms of the categories + * of data being collected. For example, JavaScript errors, page load + * performance, user journeys and user interactions are data collection + * categories. However, there is not a 1-1 mapping between data collection + * categories and plugins. + * + * This configuration option allows application owners to define the data + * categories they want to collect without needing to understand and + * instantiate each plugin themselves. The toolkit will instantiate the + * plugins which map to the selected categories. + */ + telemetries?: string[]; +}; + +export const defaultConfig: Config = { + allowCookies: false, + batchLimit: 100, + dispatchInterval: 5 * 1000, + endpoint: 'https://dataplane.us-west-2.gamma.rum.aws.dev', + eventCacheSize: 200, + eventPluginsToLoad: [], + pageIdFormat: PAGE_ID_FORMAT.PATH, + pagesToExclude: [], + pagesToInclude: [], + sessionEventLimit: 200, + sessionLengthSeconds: 60 * 30, + sessionSampleRate: 1, + userIdRetentionDays: 0, + telemetries: [ + TELEMETRY_TYPES.ERRORS, + TELEMETRY_TYPES.PERFORMANCE, + TELEMETRY_TYPES.JOURNEY, + TELEMETRY_TYPES.INTERACTION + ] +}; + +export type Config = { + allowCookies: boolean; + batchLimit: number; + clientBuilder?: ClientBuilder; + dispatchInterval: number; + endpoint: string; + eventCacheSize: number; + eventPluginsToLoad: Plugin[]; + /* + * We must remember the fetch function before the HttpFetch plugin + * overwrites it via monkey patch. We will use the original fetch function + * so that we do not record requests made by the RUM web client. + */ + fetchFunction?: ( + input: RequestInfo, + init?: RequestInit + ) => Promise; + guestRoleArn?: string; + identityPoolId?: string; + pageIdFormat: PAGE_ID_FORMAT; + pagesToExclude: RegExp[]; + pagesToInclude: RegExp[]; + sessionEventLimit: number; + sessionLengthSeconds: number; + sessionSampleRate: number; + userIdRetentionDays: number; + telemetries: string[]; +}; + +/** + * An orchestrator which (1) initializes cwr components and (2) provides the API for the application to interact + * with the RUM web client. Depending on how the RUM web client was loaded, this class may be called directly, or + * indirectly through the CommandQueue: + * - If the client was loaded by an HTML script tag, Orchestration is called indirectly through the CommandQueue. + * - If the client was loaded as an NPM module, Orchestration is called directly by the application. + */ +export class Orchestration { + private pluginManager: PluginManager; + private eventCache: EventCache; + private dispatchManager: Dispatch; + private config: Config; + + constructor( + applicationId: string, + applicationName: string, + applicationVersion: string, + region: string, + partialConfig: PartialConfig = {} + ) { + if (typeof region === 'undefined') { + // Provide temporary backwards compatability if the region was not provided by the loader. This will be + // removed when internal users have migrated to the new signature. + region = 'us-west-2'; + } + + this.config = { + ...{ fetchFunction: fetch }, + ...defaultConfig, + ...partialConfig + } as Config; + + this.config.endpoint = this.getDataPlaneEndpoint(region, partialConfig); + + this.eventCache = this.initEventCache( + applicationId, + applicationName, + applicationVersion + ); + + this.dispatchManager = this.initDispatch(region, applicationId); + this.pluginManager = this.initPluginManager( + applicationId, + applicationName, + applicationVersion + ); + } + + /** + * Set the credential provider that will be used to authenticate with the + * data plane service (AWS auth). + * @param credentials A provider of AWS credentials. + */ + public setAwsCredentials( + credentials: Credentials | CredentialProvider + ): void { + this.dispatchManager.setAwsCredentials(credentials); + } + + /** + * Add an event plugin for collecting telemetry. + * @param plugin A plugin which adheres to the RUM web client's plugin interface. + * @param config An initial configuration for the plugin. + */ + public addPlugin(plugin: Plugin, config?: any): void { + this.pluginManager.addPlugin(plugin, config); + } + + /** + * Configure a plugin. + * @param pluginId A unique identifier for the plugin being configured. + * @param config A configuration for the plugin (e.g., enable/disable events). + */ + public configurePlugin(pluginId: string, config: object): void { + this.pluginManager.configurePlugin(pluginId, config); + } + + /** + * Force the cllient to immediately dispatch events to the collector. + */ + public dispatch(): void { + this.dispatchManager.dispatchFetch(); + } + + /** + * Force the cllient to immediately dispatch events to the collector using a beacon. + */ + public dispatchBeacon(): void { + this.dispatchManager.dispatchBeacon(); + } + + /** + * When enabled, the client records and dispatches events. + */ + public enable(): void { + this.eventCache.enable(); + this.pluginManager.enable(); + this.dispatchManager.enable(); + } + + /** + * When disabled, the client does not record or dispatch events. + */ + public disable(): void { + this.dispatchManager.disable(); + this.pluginManager.disable(); + this.eventCache.disable(); + } + + /** + * @param allow when {@code false}, the RUM web client will not store cookies or use localstorage. + */ + public allowCookies(allow: boolean) { + this.config.allowCookies = allow; + } + + /** + * Update the current page the user is interacting with. + * @param pageId The unique ID for the page within the application. + */ + public recordPageView(pageId: string) { + this.eventCache.recordPageView(pageId); + } + + /** + * Record an error using the JS error plugin. + * @param error An ErrorEvent, Error or primitive. + */ + public recordError(error: any) { + this.pluginManager.record(JS_ERROR_EVENT_PLUGIN_ID, error); + } + + private initEventCache( + applicationId: string, + applicationName: string, + applicationVersion: string + ): EventCache { + return new EventCache( + { + id: applicationId, + name: applicationName, + version: applicationVersion + }, + this.config + ); + } + + private initDispatch(region: string, applicationId: string) { + const dispatchInterval: number = + typeof this.config.dispatchInterval === 'number' + ? this.config.dispatchInterval + : DEFAULT_DISPATCH_INTERVAL; + + const dispatch: Dispatch = new Dispatch( + applicationId, + region, + this.config.endpoint, + this.eventCache, + this.config + ); + + if (this.config.identityPoolId && this.config.guestRoleArn) { + dispatch.setAwsCredentials( + new Authentication(this.config) + .ChainAnonymousCredentialsProvider + ); + } else if (this.config.identityPoolId) { + dispatch.setAwsCredentials( + new EnhancedAuthentication(this.config) + .ChainAnonymousCredentialsProvider + ); + } + + return dispatch; + } + + private initPluginManager( + applicationId: string, + applicationName: string, + applicationVersion: string + ) { + const BUILTIN_PLUGINS: Plugin[] = this.constructBuiltinPlugins(); + const PLUGINS: Plugin[] = [ + ...BUILTIN_PLUGINS, + ...this.config.eventPluginsToLoad + ]; + + const pluginContext: PluginContext = { + applicationId, + applicationName, + applicationVersion, + config: this.config, + record: this.eventCache.recordEvent, + recordPageView: this.eventCache.recordPageView, + getSession: this.eventCache.getSession + }; + + // Initialize PluginManager + const pluginManager: PluginManager = new PluginManager(pluginContext); + + // Load plugins + PLUGINS.forEach((p) => { + pluginManager.addPlugin(p); + }); + + return pluginManager; + } + + private constructBuiltinPlugins(): Plugin[] { + let plugins: Plugin[] = []; + const functor: DataCollectionFunctor = this.telemetryFunctor(); + + this.config.telemetries.forEach((type) => { + if (typeof type === 'string' && functor[type.toLowerCase()]) { + plugins = [...plugins, ...functor[type.toLowerCase()]()]; + } + }); + + return plugins; + } + + private getDataPlaneEndpoint( + region: string, + partialConfig: PartialConfig + ): string { + return partialConfig.endpoint + ? partialConfig.endpoint + : DATA_PLANE_DEFAULT_ENDPOINT.replace( + DATA_PLANE_REGION_PLACEHOLDER, + region + ); + } + + /** + * Returns a functor which maps data collection categories to + * instantiated plugins. + */ + private telemetryFunctor(): DataCollectionFunctor { + return { + [TELEMETRY_TYPES.ERRORS]: (): Plugin[] => { + return [new JsErrorPlugin()]; + }, + [TELEMETRY_TYPES.PERFORMANCE]: (): Plugin[] => { + return [ + new NavigationPlugin(), + new PaintPlugin(this.config.endpoint), + new ResourcePlugin(this.config.endpoint), + new WebVitalsPlugin() + ]; + }, + [TELEMETRY_TYPES.JOURNEY]: (): Plugin[] => { + return []; + }, + [TELEMETRY_TYPES.INTERACTION]: (): Plugin[] => { + return [new DomEventPlugin()]; + }, + [TELEMETRY_TYPES.HTTP]: (): Plugin[] => { + return [new XhrPlugin(), new FetchPlugin()]; + }, + [TELEMETRY_TYPES.SINGLE_PAGE_APP_VIEWS]: (): Plugin[] => { + return [new PageViewPlugin()]; + } + }; + } +} diff --git a/src/orchestration/__tests__/Orchestration.test.ts b/src/orchestration/__tests__/Orchestration.test.ts new file mode 100644 index 00000000..5520045d --- /dev/null +++ b/src/orchestration/__tests__/Orchestration.test.ts @@ -0,0 +1,177 @@ +import { TELEMETRY_TYPES, Orchestration } from '../Orchestration'; +import { Dispatch } from '../../dispatch/Dispatch'; + +// @ts-ignore +global.fetch = jest.fn(); + +jest.mock('../../dispatch/Dispatch', () => ({ + Dispatch: jest.fn().mockImplementation(() => ({})) +})); + +jest.mock('../../event-cache/EventCache', () => ({ + EventCache: jest.fn().mockImplementation(() => ({})) +})); + +const addPlugin = jest.fn(); + +jest.mock('../../plugins/PluginManager', () => ({ + PluginManager: jest.fn().mockImplementation(() => ({ + addPlugin: addPlugin + })) +})); + +describe('Orchestration tests', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + test('when region is not provided then endpoint region defaults to us-west-2', async () => { + // Init + // @ts-ignore + const orchestration = new Orchestration('a', 'b', 'c', undefined, {}); + + // Assert + expect(Dispatch).toHaveBeenCalledTimes(1); + // @ts-ignore + expect(Dispatch.mock.calls[0][2]).toEqual( + 'https://dataplane.us-west-2.gamma.rum.aws.dev' + ); + }); + + test('when region is provided then the endpoint uses that region', async () => { + // Init + // @ts-ignore + const orchestration = new Orchestration('a', 'b', 'c', 'us-east-1', {}); + + // Assert + expect(Dispatch).toHaveBeenCalledTimes(1); + // @ts-ignore + expect(Dispatch.mock.calls[0][2]).toEqual( + 'https://dataplane.us-east-1.gamma.rum.aws.dev' + ); + }); + + test('data collection defaults to errors, performance, journey and interaction', async () => { + // Init + // @ts-ignore + const orchestration = new Orchestration('a', 'b', 'c', 'us-east-1', {}); + const expected = [ + 'com.amazonaws.rum.js-error', + 'com.amazonaws.rum.navigation', + 'com.amazonaws.rum.paint', + 'com.amazonaws.rum.resource', + 'com.amazonaws.rum.web-vitals', + 'com.amazonaws.rum.dom-event' + ]; + const actual = []; + + // Assert + expect(addPlugin).toHaveBeenCalledTimes(expected.length); + + addPlugin.mock.calls.forEach((call) => { + actual.push(call[0].getPluginId()); + }); + + expect(actual.sort()).toEqual(expected.sort()); + }); + + test('when http data collection is set then the http plugins are instantiated', async () => { + // Init + // @ts-ignore + const orchestration = new Orchestration('a', 'b', 'c', 'us-east-1', { + telemetries: ['http'] + }); + const expected = ['com.amazonaws.rum.xhr', 'com.amazonaws.rum.fetch']; + const actual = []; + + // Assert + expect(addPlugin).toHaveBeenCalledTimes(expected.length); + + addPlugin.mock.calls.forEach((call) => { + actual.push(call[0].getPluginId()); + }); + + expect(actual.sort()).toEqual(expected.sort()); + }); + + test('when performance data collection is set then the performance plugins are instantiated', async () => { + // Init + // @ts-ignore + const orchestration = new Orchestration('a', 'b', 'c', 'us-east-1', { + telemetries: ['performance'] + }); + const expected = [ + 'com.amazonaws.rum.navigation', + 'com.amazonaws.rum.paint', + 'com.amazonaws.rum.resource', + 'com.amazonaws.rum.web-vitals' + ]; + const actual = []; + + // Assert + expect(addPlugin).toHaveBeenCalledTimes(expected.length); + + addPlugin.mock.calls.forEach((call) => { + actual.push(call[0].getPluginId()); + }); + + expect(actual.sort()).toEqual(expected.sort()); + }); + + test('when error data collection is set then the error plugins are instantiated', async () => { + // Init + // @ts-ignore + const orchestration = new Orchestration('a', 'b', 'c', 'us-east-1', { + telemetries: ['errors'] + }); + const expected = ['com.amazonaws.rum.js-error']; + const actual = []; + + // Assert + expect(addPlugin).toHaveBeenCalledTimes(expected.length); + + addPlugin.mock.calls.forEach((call) => { + actual.push(call[0].getPluginId()); + }); + + expect(actual.sort()).toEqual(expected.sort()); + }); + + test('when interaction data collection is set then the interaction plugins are instantiated', async () => { + // Init + // @ts-ignore + const orchestration = new Orchestration('a', 'b', 'c', 'us-east-1', { + telemetries: ['interaction'] + }); + const expected = ['com.amazonaws.rum.dom-event']; + const actual = []; + + // Assert + expect(addPlugin).toHaveBeenCalledTimes(expected.length); + + addPlugin.mock.calls.forEach((call) => { + actual.push(call[0].getPluginId()); + }); + + expect(actual.sort()).toEqual(expected.sort()); + }); + + test('when single page application views data collection is set then the page event plugin is instantiated', async () => { + // Init + // @ts-ignore + const orchestration = new Orchestration('a', 'b', 'c', 'us-east-1', { + telemetries: [TELEMETRY_TYPES.SINGLE_PAGE_APP_VIEWS] + }); + const expected = ['com.amazonaws.rum.page-view']; + const actual = []; + + // Assert + expect(addPlugin).toHaveBeenCalledTimes(expected.length); + + addPlugin.mock.calls.forEach((call) => { + actual.push(call[0].getPluginId()); + }); + + expect(actual.sort()).toEqual(expected.sort()); + }); +}); diff --git a/src/plugins/MonkeyPatched.ts b/src/plugins/MonkeyPatched.ts new file mode 100644 index 00000000..ecc5122d --- /dev/null +++ b/src/plugins/MonkeyPatched.ts @@ -0,0 +1,24 @@ +import * as shimmer from 'shimmer'; + +export type MonkeyPatch = { + nodule: object; + name: string; + // tslint:disable-next-line: ban-types + wrapper: Function; +}; + +export abstract class MonkeyPatched { + public enable() { + for (const patch of this.patches()) { + shimmer.wrap(patch.nodule, patch.name, patch.wrapper()); + } + } + + public disable() { + for (const patch of this.patches()) { + shimmer.unwrap(patch.nodule, patch.name); + } + } + + protected abstract patches(): MonkeyPatch[]; +} diff --git a/src/plugins/Plugin.ts b/src/plugins/Plugin.ts new file mode 100644 index 00000000..3f4a2c25 --- /dev/null +++ b/src/plugins/Plugin.ts @@ -0,0 +1,54 @@ +import { Config } from '../orchestration/Orchestration'; +import { Session } from '../sessions/SessionManager'; + +export type RecordEvent = (type: string, eventData: object) => void; +export type RecordPageView = (pageId: string) => void; + +export type GetSession = () => Session; + +export type PluginContext = { + applicationId: string; + applicationName: string; + applicationVersion: string; + config: Config; + record: RecordEvent; + recordPageView: RecordPageView; + getSession: GetSession; +}; + +export interface Plugin { + /** + * Load the plugin. The plugin should initialize itself and start recording events + * for which it is configured. + * @param recordEvent A callback to record event data. + */ + load(context: PluginContext): void; + + /** + * Enable the plugin. The plugin may record events. + */ + enable(): void; + + /** + * Disable the plugin. The plugin should remove event listeners and cease recording events. + */ + disable(): void; + + /** + * Returns a unique identifier for the plugin. + */ + getPluginId(): string; + + /** + * Configure the plugin. The plugin should start or stop recording events for + * which it is configured. + * @param config The configuration for the plugin (e.g., enable/disable events). + */ + configure(config: object): void; + + /** + * Manually record an event. + * @param data Data that the plugin will use to create an event. + */ + record?(data: any): void; +} diff --git a/src/plugins/PluginManager.ts b/src/plugins/PluginManager.ts new file mode 100644 index 00000000..71f144bc --- /dev/null +++ b/src/plugins/PluginManager.ts @@ -0,0 +1,94 @@ +import { Plugin, PluginContext } from './Plugin'; + +/** + * The plugin manager maintains a list of plugins + * and notifies plugins of configuration or lifecycle changes. + */ +export class PluginManager { + private plugins: Map; + private context: PluginContext; + + constructor(context: PluginContext) { + this.plugins = new Map(); + this.context = context; + } + + /** + * Add an event plugin to PluginManager. + * It also: + * 1. config the plugin with in intial configuration + * 2. initialize the plugin + * @param plugin The plugin which adheres to the RUM web client's plugin interface. + * @param config The initial configuration for the plugin. + */ + public addPlugin(plugin: Plugin, config?: any): void { + const pluginId: string = plugin.getPluginId(); + + // add to plugin map + if (pluginId) { + this.plugins.set(pluginId, plugin); + } else { + throw new Error('InvalidPluginIdException'); + } + + // initialize plugin + plugin.load(this.context); + + // config plugin + if (config) { + plugin.configure(config); + } + } + + /** + * Enable all event plugins. + */ + public enable() { + this.plugins.forEach((p) => p.enable()); + } + + /** + * Disable all event plugins. + */ + public disable() { + this.plugins.forEach((p) => p.disable()); + } + + /** + * Return if a plugin exists. + * @param pluginId a unique identifier for the plugin + */ + public hasPlugin(pluginId: string): boolean { + return this.plugins.has(pluginId); + } + + /** + * Configure a plugin. + * @param pluginId The unique identifier for the plugin being configured. + * @param config The configuration for the plugin (e.g., enable/disable events). + */ + public configurePlugin(pluginId: string, config: object): void { + const plugin = this.plugins.get(pluginId); + if (plugin) { + plugin.configure(config); + } else { + throw new Error( + 'AWS RUM Client configurePlugin: Invalid plugin ID' + ); + } + } + + /** + * Manually record data using a plugin. + * @param pluginId The unique identifier for the plugin being configured. + * @param data The data to be recorded by the plugin. + */ + public record(pluginId: string, data: any): void { + const plugin = this.plugins.get(pluginId); + if (plugin && plugin.record instanceof Function) { + plugin.record(data); + } else { + throw new Error('AWS RUM Client record: Invalid plugin ID'); + } + } +} diff --git a/src/plugins/__tests__/plugins.test.ts b/src/plugins/__tests__/plugins.test.ts new file mode 100644 index 00000000..1e2642d6 --- /dev/null +++ b/src/plugins/__tests__/plugins.test.ts @@ -0,0 +1,76 @@ +import { PluginManager } from '../PluginManager'; +import { + DemoPlugin, + DEMO_EVENT_TYPE, + DEMO_PLUGIN_ID +} from '../event-plugins/DemoPlugin'; +import { context } from '../../test-utils/test-utils'; + +describe('Plugins tests', () => { + test('add a valid plugin', async () => { + // Init + const pluginManager: PluginManager = new PluginManager(context); + const demoPlugin: DemoPlugin = new DemoPlugin(); + + // Run + pluginManager.addPlugin(demoPlugin, {}); + + // Assert + expect(pluginManager.hasPlugin(demoPlugin.getPluginId())).toBeTruthy(); + }); + + test('update a plugin', async () => { + // Init + const pluginManager: PluginManager = new PluginManager(context); + const demoPlugin: DemoPlugin = new DemoPlugin(); + + // Run + pluginManager.addPlugin(demoPlugin, { enable: true }); + + // Assert + expect(demoPlugin.configuration.enable).toEqual(true); + + // update plugin config + pluginManager.configurePlugin(DEMO_PLUGIN_ID, { enable: false }); + + // Assert + expect(demoPlugin.configuration.enable).toEqual(false); + }); + + test('when an invalid plugin is configured then the plugin manager throws an error', async () => { + // Init + const pluginManager: PluginManager = new PluginManager(context); + + // Run and Assert + expect(() => + pluginManager.configurePlugin('does_not_exist', {}) + ).toThrowError( + new Error('AWS RUM Client configurePlugin: Invalid plugin ID') + ); + }); + + test('when data is recorded to an invalid plugin then the plugin manager throws an error', async () => { + // Init + const pluginManager: PluginManager = new PluginManager(context); + + // Run and Assert + expect(() => pluginManager.record('does_not_exist', {})).toThrowError( + new Error('AWS RUM Client record: Invalid plugin ID') + ); + }); + + test('when the application manually records data then the plugin records the error', async () => { + // Init + const pluginManager: PluginManager = new PluginManager(context); + const demoPlugin: DemoPlugin = new DemoPlugin(); + pluginManager.addPlugin(demoPlugin, { enable: true }); + + // Run + pluginManager.record(DEMO_PLUGIN_ID, 'data to record'); + + // Assert + expect(context.record).toHaveBeenCalledTimes(1); + // @ts-ignore + expect(context.record.mock.calls[0][0]).toEqual(DEMO_EVENT_TYPE); + }); +}); diff --git a/src/plugins/event-plugins/DemoPlugin.ts b/src/plugins/event-plugins/DemoPlugin.ts new file mode 100644 index 00000000..88c59cad --- /dev/null +++ b/src/plugins/event-plugins/DemoPlugin.ts @@ -0,0 +1,71 @@ +import { RecordEvent, Plugin, PluginContext } from '../Plugin'; + +export const DEMO_EVENT_TYPE = 'com.amazon.rum.demo_event'; +export const DEMO_PLUGIN_ID = 'com.amazonaws.rum.demo'; + +/** + * The demo plugin is a dummy plugins. The demo plugin: + * 1. Trigger a dummy activity every 1 sec. + * 2. Call back to the session manager to record the demo event data. + */ + +export class DemoPlugin implements Plugin { + configuration: any; + timerId: number | undefined; + private recordEvent: RecordEvent | undefined; + + constructor() { + this.configuration = {}; + this.timerId = undefined; + } + + load(context: PluginContext): void { + this.recordEvent = context.record; + this.enable(); + } + + enable(): void { + // dummy activity every 1 sec + if (!this.timerId) { + this.timerId = window.setInterval(() => { + if (this.recordEvent) { + this.eventHandler(this.recordEvent); + } + }, 1_000); + } + } + + disable(): void { + if (this.timerId) { + window.clearInterval(this.timerId); + this.timerId = undefined; + } + } + + getPluginId(): string { + return DEMO_PLUGIN_ID; + } + + configure(config: object): void { + this.configuration = { + ...this.configuration, + ...config + }; + } + + record(data: any): void { + const demoEvent = { + eventData: data + }; + this.recordEvent(DEMO_EVENT_TYPE, demoEvent); + } + + private eventHandler(recordEvent: RecordEvent): void { + if (this.configuration.enable) { + const demoEvent = { + eventData: 'demoEventData' + }; + recordEvent(DEMO_EVENT_TYPE, demoEvent); + } + } +} diff --git a/src/plugins/event-plugins/DomEventPlugin.ts b/src/plugins/event-plugins/DomEventPlugin.ts new file mode 100644 index 00000000..14008de4 --- /dev/null +++ b/src/plugins/event-plugins/DomEventPlugin.ts @@ -0,0 +1,136 @@ +import { RecordEvent, Plugin, PluginContext } from '../Plugin'; +import { DomEvent } from '../../events/dom-event'; +import { DOM_EVENT_TYPE } from '../utils/constant'; + +export const DOM_EVENT_PLUGIN_ID = 'com.amazonaws.rum.dom-event'; + +export type TargetDomEvent = { + /** + * DOM event type (e.g., click, scroll, hover, etc.) + */ + event: string; + + /** + * DOM element ID. + */ + elementId?: string; + + /** + * DOM element + */ + element?: HTMLElement; +}; + +export class DomEventPlugin implements Plugin { + private recordEvent: RecordEvent | undefined; + private configuration: TargetDomEvent[] = []; + private pluginId: string; + private eventListenerMap: Map; + private enabled: boolean; + + constructor() { + this.pluginId = DOM_EVENT_PLUGIN_ID; + this.eventListenerMap = new Map(); + this.enabled = true; + } + + load(context: PluginContext): void { + this.recordEvent = context.record; + } + + enable(): void { + if (this.enabled) { + return; + } + this.addListeners(this.configuration); + this.enabled = true; + } + + disable(): void { + if (!this.enabled) { + return; + } + this.removeListeners(this.configuration); + this.enabled = false; + } + + getPluginId(): string { + return this.pluginId; + } + + configure(config: any): void { + if (this.enabled) { + this.removeListeners(this.configuration); + this.addListeners(config); + } + this.configuration = config; + } + + private removeListeners(config: TargetDomEvent[]) { + config.forEach((domEvent) => this.removeEventHandler(domEvent)); + } + + private addListeners(config: TargetDomEvent[]) { + config.forEach((domEvent) => this.addEventHandler(domEvent)); + } + + private getEventListener(): EventListener { + return (event: Event): void => { + // @ts-ignore + const eventData: DomEvent = { + version: '1.0.0', + event: event.type, + elementId: this.getElementId(event) + }; + if (this.recordEvent) { + this.recordEvent(DOM_EVENT_TYPE, eventData); + } + }; + } + + private getElementId(event: Event) { + if (!event.target) { + return ''; + } + + if (event.target instanceof Element && event.target.id) { + return event.target.id; + } + + if (event.target instanceof Node) { + return event.target.nodeName; + } + + return ''; + } + + private addEventHandler(domEvent: TargetDomEvent): void { + const eventType = domEvent.event; + const eventListener = this.getEventListener(); + this.eventListenerMap.set(domEvent, eventListener); + + if (domEvent.elementId) { + document + .getElementById(domEvent.elementId) + ?.addEventListener(eventType, eventListener); + } else if (domEvent.element) { + domEvent.element.addEventListener(eventType, eventListener); + } + } + + private removeEventHandler(domEvent: TargetDomEvent): void { + const eventListener: + | EventListener + | undefined = this.eventListenerMap.get(domEvent); + + if (domEvent.elementId && eventListener) { + const element = document.getElementById(domEvent.elementId); + if (element) { + element.removeEventListener(domEvent.event, eventListener); + } + } else if (domEvent.element && eventListener) { + domEvent.element.removeEventListener(domEvent.event, eventListener); + } + this.eventListenerMap.delete(domEvent); + } +} diff --git a/src/plugins/event-plugins/FetchPlugin.ts b/src/plugins/event-plugins/FetchPlugin.ts new file mode 100644 index 00000000..7d6ea000 --- /dev/null +++ b/src/plugins/event-plugins/FetchPlugin.ts @@ -0,0 +1,241 @@ +import { Plugin, PluginContext } from '../Plugin'; +import { Http, XRayTraceEvent } from '../../events/xray-trace-event'; +import { MonkeyPatch, MonkeyPatched } from '../MonkeyPatched'; +import { + HttpPluginConfig, + defaultConfig, + epochTime, + createXRayTraceEvent, + addAmznTraceIdHeader, + HttpPluginConfigWithDefaults, + createXRayTraceEventHttp, + isUrlAllowed +} from '../utils/http-utils'; +import { HTTP_EVENT_TYPE, XRAY_TRACE_EVENT_TYPE } from '../utils/constant'; +import { errorEventToJsErrorEvent } from '../utils/js-error-utils'; +import { HttpEvent } from '../../events/http-event'; + +type Fetch = (input: RequestInfo, init?: RequestInit) => Promise; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error + */ +type Error = { + message: string; + name: string; + fileName?: string; // non-standard Mozilla + lineNumber?: number; // non-standard Mozilla + columnNumber?: number; // non-standard Mozilla + stack?: string; // non-standard Mozilla +}; + +export const FETCH_PLUGIN_ID = 'com.amazonaws.rum.fetch'; + +/** + * A plugin which initiates and records AWS X-Ray traces for fetch HTTP requests. + * + * The fetch API is monkey patched using shimmer so all calls to fetch are intercepted. Only calls to URLs which are + * on the allowlist and are not on the denylist are traced and recorded. + */ +export class FetchPlugin extends MonkeyPatched implements Plugin { + private pluginId: string; + private config: HttpPluginConfigWithDefaults; + private context: PluginContext; + + constructor(config?: HttpPluginConfig) { + super(); + this.pluginId = FETCH_PLUGIN_ID; + this.config = { ...defaultConfig, ...config }; + } + + public load(context: PluginContext): void { + this.context = context; + this.enable(); + } + + public getPluginId(): string { + return this.pluginId; + } + + public configure(config: HttpPluginConfig): void { + this.config = { ...this.config, ...config }; + } + + protected patches(): MonkeyPatch[] { + return [ + { + nodule: window, + name: 'fetch', + wrapper: this.fetchWrapper + } + ]; + } + + private isTracingEnabled = () => { + return this.config.trace; + }; + + private isSessionRecorded = () => { + return this.context.getSession().record; + }; + + private beginTrace = ( + input: RequestInfo, + init: RequestInit + ): XRayTraceEvent => { + const startTime = epochTime(); + const http: Http = createXRayTraceEventHttp(input, init, true); + const xRayTraceEvent: XRayTraceEvent = createXRayTraceEvent( + this.config.logicalServiceName, + startTime, + http + ); + + addAmznTraceIdHeader(init, xRayTraceEvent.trace_id, xRayTraceEvent.id); + + return xRayTraceEvent; + }; + + private endTrace = ( + xRayTraceEvent: XRayTraceEvent, + response: Response | undefined, + error: Error | string | number | boolean | undefined + ) => { + if (xRayTraceEvent) { + const endTime = epochTime(); + xRayTraceEvent.end_time = endTime; + + if (response) { + xRayTraceEvent.http.response = { + status: response.status + }; + } + + if (error) { + xRayTraceEvent.error = true; + if (error instanceof Object) { + this.appendErrorCauseFromObject(xRayTraceEvent, error); + } else { + this.appendErrorCauseFromPrimitive(xRayTraceEvent, error); + } + } + + this.context.record(XRAY_TRACE_EVENT_TYPE, xRayTraceEvent); + } + }; + + private appendErrorCauseFromPrimitive( + xRayTraceEvent: XRayTraceEvent, + error: any + ) { + xRayTraceEvent.cause = { + exceptions: [ + { + type: error.toString() + } + ] + }; + } + + private appendErrorCauseFromObject( + xRayTraceEvent: XRayTraceEvent, + error: Error + ) { + xRayTraceEvent.cause = { + exceptions: [ + { + type: error.name, + message: error.message + } + ] + }; + } + + private createHttpEvent = ( + input: RequestInfo, + init: RequestInit + ): HttpEvent => { + return { + version: '1.0.0', + request: { + method: init.method ? init.method : 'GET', + url: input.toString() + } + }; + }; + + private recordHttpEventWithResponse = ( + httpEvent: HttpEvent, + response: Response + ) => { + if (this.config.recordAllRequests || !response.ok) { + httpEvent.response = { + status: response.status, + statusText: response.statusText + }; + this.context.record(HTTP_EVENT_TYPE, httpEvent); + } + }; + + private recordHttpEventWithError = ( + httpEvent: HttpEvent, + error: Error | string | number | boolean | undefined | null + ) => { + httpEvent.error = errorEventToJsErrorEvent( + { + type: 'error', + error + } as ErrorEvent, + this.config.stackTraceLength + ); + this.context.record(HTTP_EVENT_TYPE, httpEvent); + }; + + private fetch = ( + original: Fetch, + thisArg: Fetch, + argsArray: IArguments, + input: RequestInfo, + init?: RequestInit + ): Promise => { + init = init ? init : {}; + const httpEvent: HttpEvent = this.createHttpEvent(input, init); + let trace: XRayTraceEvent | undefined; + + if (!isUrlAllowed(input.toString(), this.config)) { + return original.apply(thisArg, argsArray); + } + + if (this.isTracingEnabled() && this.isSessionRecorded()) { + trace = this.beginTrace(input, init); + } + + return original + .apply(thisArg, argsArray) + .then((response: Response) => { + this.endTrace(trace, response, undefined); + this.recordHttpEventWithResponse(httpEvent, response); + return response; + }) + .catch((error: Error) => { + this.endTrace(trace, undefined, error); + this.recordHttpEventWithError(httpEvent, error); + throw error; + }); + }; + + private fetchWrapper = (): (( + original: (input: RequestInfo, init?: RequestInit) => Promise + ) => (input: RequestInfo, init?: RequestInit) => Promise) => { + const self = this; + return (original: Fetch): Fetch => { + return function ( + this: Fetch, + input: RequestInfo, + init?: RequestInit + ): Promise { + return self.fetch(original, this, arguments, input, init); + }; + }; + }; +} diff --git a/src/plugins/event-plugins/JsErrorPlugin.ts b/src/plugins/event-plugins/JsErrorPlugin.ts new file mode 100644 index 00000000..2ff233f2 --- /dev/null +++ b/src/plugins/event-plugins/JsErrorPlugin.ts @@ -0,0 +1,78 @@ +import { RecordEvent, Plugin, PluginContext } from '../Plugin'; +import { JS_ERROR_EVENT_TYPE } from '../utils/constant'; +import { errorEventToJsErrorEvent } from '../utils/js-error-utils'; + +export const JS_ERROR_EVENT_PLUGIN_ID = 'com.amazonaws.rum.js-error'; + +export type JsErrorPluginConfig = { + stackTraceLength: number; +}; + +const defaultConfig: JsErrorPluginConfig = { + stackTraceLength: 200 +}; + +export class JsErrorPlugin implements Plugin { + private pluginId: string; + private enabled: boolean; + private config: JsErrorPluginConfig; + private recordEvent: RecordEvent; + + constructor(config?: JsErrorPluginConfig) { + this.pluginId = JS_ERROR_EVENT_PLUGIN_ID; + this.enabled = true; + this.config = config ? config : defaultConfig; + } + + load(context: PluginContext): void { + this.recordEvent = context.record; + this.addEventHandler(); + } + + enable(): void { + if (this.enabled) { + return; + } + this.addEventHandler(); + this.enabled = true; + } + + disable(): void { + if (!this.enabled) { + return; + } + this.removeEventHandler(); + this.enabled = false; + } + + getPluginId(): string { + return this.pluginId; + } + + configure(config: JsErrorPluginConfig): void { + this.config = config; + } + + record(error: any): void { + if (error instanceof ErrorEvent) { + this.eventHandler(error); + } else { + this.eventHandler({ type: 'error', error } as ErrorEvent); + } + } + + private eventHandler = (errorEvent: ErrorEvent) => { + this.recordEvent( + JS_ERROR_EVENT_TYPE, + errorEventToJsErrorEvent(errorEvent, this.config.stackTraceLength) + ); + }; + + private addEventHandler(): void { + window.addEventListener('error', this.eventHandler); + } + + private removeEventHandler(): void { + window.removeEventListener('error', this.eventHandler); + } +} diff --git a/src/plugins/event-plugins/NavigationPlugin.ts b/src/plugins/event-plugins/NavigationPlugin.ts new file mode 100644 index 00000000..db7ef9db --- /dev/null +++ b/src/plugins/event-plugins/NavigationPlugin.ts @@ -0,0 +1,252 @@ +import { RecordEvent, Plugin, PluginContext } from '../Plugin'; +import { NavigationEvent } from '../../events/navigation-event'; +import { PERFORMANCE_NAVIGATION_EVENT_TYPE } from '../utils/constant'; + +export const NAVIGATION_EVENT_PLUGIN_ID = 'com.amazonaws.rum.navigation'; + +const NAVIGATION = 'navigation'; +const LOAD = 'load'; + +/** + * This plugin records performance timing events generated during every page load/re-load activity. + * Paint, resource and performance event types make sense only if all or none are included. + * For RUM, these event types are inter-dependent. So they are recorded under one plugin. + */ +export class NavigationPlugin implements Plugin { + private pluginId: string; + private enabled: boolean; + private recordEvent: RecordEvent | undefined; + + constructor() { + this.pluginId = NAVIGATION_EVENT_PLUGIN_ID; + this.enabled = true; + } + + load(context: PluginContext): void { + this.recordEvent = context.record; + if (this.enabled) { + window.addEventListener(LOAD, this.eventListener); + } + } + + enable(): void { + if (this.enabled) { + return; + } + this.enabled = true; + window.addEventListener(LOAD, this.eventListener); + } + + disable(): void { + if (!this.enabled) { + return; + } + this.enabled = false; + if (this.eventListener) { + window.removeEventListener(LOAD, this.eventListener); + } + } + + getPluginId(): string { + return this.pluginId; + } + + // tslint:disable:no-empty + configure(config: string[]): void {} + + /** + * Use Navigation timing Level 1 for all browsers by default - + * https://developer.mozilla.org/en-US/docs/Web/API/Performance/timing + * + * If browser provides support, use Navigation Timing Level 2 specification - + * https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigationTiming + */ + eventListener = () => { + if (performance.getEntriesByType(NAVIGATION).length === 0) { + this.performanceNavigationEventHandlerTimingLevel1(); + } else { + const navigationObserver = new PerformanceObserver((list) => { + list.getEntries().forEach((event) => { + if (event.entryType === NAVIGATION) { + this.performanceNavigationEventHandlerTimingLevel2( + event + ); + } + }); + }); + navigationObserver.observe({ + entryTypes: [NAVIGATION] + }); + } + }; + + /** + * W3C specification: https://www.w3.org/TR/navigation-timing/#sec-navigation-timing-interface + */ + performanceNavigationEventHandlerTimingLevel1 = () => { + const recordNavigation = () => { + const entryData = performance.timing; + const origin = entryData.navigationStart; + const eventDataNavigationTimingLevel1: NavigationEvent = { + version: '1.0.0', + initiatorType: 'navigation', + startTime: 0, + unloadEventStart: + entryData.unloadEventStart > 0 + ? entryData.unloadEventStart - origin + : 0, + promptForUnload: + entryData.unloadEventEnd - entryData.unloadEventStart, + redirectStart: + entryData.redirectStart > 0 + ? entryData.redirectStart - origin + : 0, + redirectTime: entryData.redirectEnd - entryData.redirectStart, + fetchStart: + entryData.fetchStart > 0 + ? entryData.fetchStart - origin + : 0, + domainLookupStart: + entryData.domainLookupStart > 0 + ? entryData.domainLookupStart - origin + : 0, + dns: entryData.domainLookupEnd - entryData.domainLookupStart, + connectStart: + entryData.connectStart > 0 + ? entryData.connectStart - origin + : 0, + connect: entryData.connectEnd - entryData.connectStart, + secureConnectionStart: + entryData.secureConnectionStart > 0 + ? entryData.secureConnectionStart - origin + : 0, + tlsTime: + entryData.secureConnectionStart > 0 + ? entryData.connectEnd - entryData.secureConnectionStart + : 0, + + requestStart: + entryData.requestStart > 0 + ? entryData.requestStart - origin + : 0, + timeToFirstByte: + entryData.responseStart - entryData.requestStart, + responseStart: + entryData.responseStart > 0 + ? entryData.responseStart - origin + : 0, + responseTime: + entryData.responseStart > 0 + ? entryData.responseEnd - entryData.responseStart + : 0, + + domInteractive: + entryData.domInteractive > 0 + ? entryData.domInteractive - origin + : 0, + domContentLoadedEventStart: + entryData.domContentLoadedEventStart > 0 + ? entryData.domContentLoadedEventStart - origin + : 0, + domContentLoaded: + entryData.domContentLoadedEventEnd - + entryData.domContentLoadedEventStart, + domComplete: + entryData.domComplete > 0 + ? entryData.domComplete - origin + : 0, + domProcessingTime: + entryData.loadEventStart - entryData.responseEnd, + loadEventStart: + entryData.loadEventStart > 0 + ? entryData.loadEventStart - origin + : 0, + loadEventTime: + entryData.loadEventEnd - entryData.loadEventStart, + duration: entryData.loadEventEnd - entryData.navigationStart, + navigationTimingLevel: 1 + }; + if (this.recordEvent) { + this.recordEvent( + PERFORMANCE_NAVIGATION_EVENT_TYPE, + eventDataNavigationTimingLevel1 + ); + } + }; + // Timeout is required for loadEventEnd to complete + setTimeout(recordNavigation, 0); + }; + + /** + * W3C specification: https://www.w3.org/TR/navigation-timing-2/#bib-navigation-timing + */ + performanceNavigationEventHandlerTimingLevel2 = (entryData: any): void => { + const eventDataNavigationTimingLevel2: NavigationEvent = { + version: '1.0.0', + targetUrl: entryData.name, + initiatorType: entryData.initiatorType, + navigationType: entryData.type, + startTime: entryData.startTime, + unloadEventStart: entryData.unloadEventStart, + promptForUnload: + entryData.unloadEventEnd - entryData.unloadEventStart, + redirectCount: entryData.redirectCount, + redirectStart: entryData.redirectStart, + redirectTime: entryData.redirectEnd - entryData.redirectStart, + + workerStart: entryData.workerStart, + workerTime: + entryData.workerStart > 0 + ? entryData.fetchStart - entryData.workerStart + : 0, + + fetchStart: entryData.fetchStart, + domainLookupStart: entryData.domainLookupStart, + dns: entryData.domainLookupEnd - entryData.domainLookupStart, + + nextHopProtocol: entryData.nextHopProtocol, + connectStart: entryData.connectStart, + connect: entryData.connectEnd - entryData.connectStart, + secureConnectionStart: entryData.secureConnectionStart, + tlsTime: + entryData.secureConnectionStart > 0 + ? entryData.connectEnd - entryData.secureConnectionStart + : 0, + + requestStart: entryData.requestStart, + timeToFirstByte: entryData.responseStart - entryData.requestStart, + responseStart: entryData.responseStart, + responseTime: + entryData.responseStart > 0 + ? entryData.responseEnd - entryData.responseStart + : 0, + + domInteractive: entryData.domInteractive, + domContentLoadedEventStart: entryData.domContentLoadedEventStart, + domContentLoaded: + entryData.domContentLoadedEventEnd - + entryData.domContentLoadedEventStart, + domComplete: entryData.domComplete, + domProcessingTime: entryData.loadEventStart - entryData.responseEnd, + loadEventStart: entryData.loadEventStart, + loadEventTime: entryData.loadEventEnd - entryData.loadEventStart, + + duration: entryData.duration, + + headerSize: entryData.transferSize - entryData.encodedBodySize, + transferSize: entryData.transferSize, + compressionRatio: + entryData.encodedBodySize > 0 + ? entryData.decodedBodySize / entryData.encodedBodySize + : 0, + navigationTimingLevel: 2 + }; + + if (this.recordEvent) { + this.recordEvent( + PERFORMANCE_NAVIGATION_EVENT_TYPE, + eventDataNavigationTimingLevel2 + ); + } + }; +} diff --git a/src/plugins/event-plugins/PageViewPlugin.ts b/src/plugins/event-plugins/PageViewPlugin.ts new file mode 100644 index 00000000..47be7d06 --- /dev/null +++ b/src/plugins/event-plugins/PageViewPlugin.ts @@ -0,0 +1,120 @@ +import { PAGE_ID_FORMAT } from '../../orchestration/Orchestration'; +import { MonkeyPatch, MonkeyPatched } from '../MonkeyPatched'; +import { Plugin, PluginContext } from '../Plugin'; + +export const PAGE_EVENT_PLUGIN_ID = 'com.amazonaws.rum.page-view'; + +export type Push = (data: any, title: string, url?: string | null) => void; +export type Replace = (data: any, title: string, url?: string | null) => void; + +/** + * A plugin which records page view transitions. + * + * When a session is initialized, the PageManager records the landing page. When + * subsequent pages are viewed, this plugin updates the page. + */ +export class PageViewPlugin extends MonkeyPatched implements Plugin { + private pluginId: string; + private context: PluginContext; + + constructor() { + super(); + this.pluginId = PAGE_EVENT_PLUGIN_ID; + this.enable(); + } + + public load(context: PluginContext): void { + this.context = context; + this.addListener(); + } + + public getPluginId(): string { + return this.pluginId; + } + + // tslint:disable-next-line:no-empty + public configure(config: any): void {} + + protected patches(): MonkeyPatch[] { + return [ + { + nodule: History.prototype, + name: 'pushState', + wrapper: this.pushState + }, + { + nodule: History.prototype, + name: 'replaceState', + wrapper: this.replaceState + } + ]; + } + + private pushState = (): ((original: Push) => Push) => { + const self = this; + return (original: Push): Push => { + return function ( + this: Push, + data: string, + title: string, + url?: string | null + ): void { + const retVal = original.apply(this, arguments); + self.recordPageView(); + return retVal; + }; + }; + }; + + private replaceState = (): ((original: Replace) => Replace) => { + const self = this; + return (original: Replace): Replace => { + return function ( + this: Replace, + data: string, + title: string, + url?: string | null + ): void { + const retVal = original.apply(this, arguments); + self.recordPageView(); + return retVal; + }; + }; + }; + + private addListener() { + // popstate will fire under the following conditions: + // (1) The history back, forward or go APIs are used + // (2) The URI's fragment (hash) changes + window.addEventListener('popstate', this.popstateListener); + } + + private popstateListener: EventListener = (event: Event) => { + this.recordPageView(); + }; + + private recordPageView = () => { + this.context.recordPageView(this.createIdForCurrentPage()); + }; + + private createIdForCurrentPage(): string { + const path = window.location.pathname; + const hash = window.location.hash; + switch (this.context.config.pageIdFormat) { + case PAGE_ID_FORMAT.PATH_AND_HASH: + if (path && hash) { + return path + hash; + } else if (path) { + return path; + } else if (hash) { + return hash; + } + return ''; + case PAGE_ID_FORMAT.HASH: + return hash ? hash : ''; + case PAGE_ID_FORMAT.PATH: + default: + return path ? path : ''; + } + } +} diff --git a/src/plugins/event-plugins/PaintPlugin.ts b/src/plugins/event-plugins/PaintPlugin.ts new file mode 100644 index 00000000..934eec0a --- /dev/null +++ b/src/plugins/event-plugins/PaintPlugin.ts @@ -0,0 +1,186 @@ +import { RecordEvent, Plugin, PluginContext } from '../Plugin'; +import { getHost } from '../../utils/common-utils'; +import { PaintEvent } from '../../events/paint-event'; +import { + PERFORMANCE_FIRST_CONTENTFUL_PAINT_EVENT_TYPE, + PERFORMANCE_FIRST_PAINT_EVENT_TYPE +} from '../utils/constant'; + +export const PAINT_EVENT_PLUGIN_ID = 'com.amazonaws.rum.paint'; + +const FIRST_PAINT = 'first-paint'; +const FIRST_CONTENTFUL_PAINT = 'first-contentful-paint'; +const PAINT = 'paint'; +const RESOURCE = 'resource'; +const LOAD = 'load'; + +/** + * This plugin records paint performance timing events generated during every + * page load/re-load. + */ +export class PaintPlugin implements Plugin { + private pluginId: string; + private enabled: boolean; + private recordEvent: RecordEvent | undefined; + + /** + * The data plane service endpoint. Resources from this endpoint will be + * ignored; i.e., this plugin will not generate resource performance events + * for them. + */ + private dataPlaneEndpoint: string; + + constructor(dataPlaneEndpoint) { + this.pluginId = PAINT_EVENT_PLUGIN_ID; + this.enabled = true; + this.dataPlaneEndpoint = dataPlaneEndpoint; + } + + load(context: PluginContext): void { + this.recordEvent = context.record; + if (this.enabled) { + window.addEventListener(LOAD, this.eventListener); + } + } + + enable(): void { + if (this.enabled) { + return; + } + this.enabled = true; + window.addEventListener(LOAD, this.eventListener); + } + + disable(): void { + if (!this.enabled) { + return; + } + this.enabled = false; + if (this.eventListener) { + window.removeEventListener(LOAD, this.eventListener); + } + } + + getPluginId(): string { + return this.pluginId; + } + + // tslint:disable:no-empty + configure(config: string[]): void {} + + eventListener: EventListener = () => { + let events: PerformanceEntryList; + let isFirstPaintAvailable = false; + events = performance.getEntriesByType(PAINT); + if (events !== undefined && events.length > 0) { + events.forEach((event) => { + if (event.name === FIRST_PAINT) { + isFirstPaintAvailable = true; + } + this.performancePaintEventHandler(event); + }); + } + + if (!isFirstPaintAvailable) { + /** + * 1. Firefox does not provide first-paint and first-contentful Paint API. + * 2. Safari does not provide first-paint API. Paint is not available in Safari + * - https://bugs.webkit.org/show_bug.cgi?id=78011 + * 3. First Paint event is derived using algorithm if not available directly. + * Refer - https://github.com/addyosmani/timing.js/issues/31 + */ + this.recordDerivedFirstPaintEvent(); + } + }; + + recordDerivedFirstPaintEvent = () => { + let events: PerformanceEntryList; + const filteredEvents = []; + + // 1. record domInteractive + const domInteractive = + performance.timing.domInteractive - + performance.timing.navigationStart; + + const resourceObserver = new PerformanceObserver((list) => { + list.getEntries().forEach((event) => { + // Out of n resource events, x events are recorded using Observer API + if ( + event.entryType === RESOURCE && + getHost(event.name) !== getHost(this.dataPlaneEndpoint) + ) { + const e = event as PerformanceResourceTiming; + // 2. Filter events with initiatorType as 'script' or 'link' with startTime less than domInteractive + if ( + (e.initiatorType === 'script' || + e.initiatorType === 'link') && + e.startTime < domInteractive + ) { + filteredEvents.push(e); + } + } + }); + }); + resourceObserver.observe({ + entryTypes: [RESOURCE] + }); + + /** + * Remaining (n-x) resource events are recorded using getEntriesByType API. + * Note: IE11 browser does not support Performance Observer API. Handle the failure gracefully + */ + events = performance.getEntriesByType(RESOURCE); + if (events !== undefined && events.length > 0) { + events.forEach((event) => { + const e = event as PerformanceResourceTiming; + // 2. Filter events with initiatorType as 'script' or 'link' with startTime less than domInteractive + if ( + (e.initiatorType === 'script' || + e.initiatorType === 'link') && + e.startTime < domInteractive && + getHost(e.name) !== getHost(this.dataPlaneEndpoint) + ) { + filteredEvents.push(e); + } + }); + } + + // 3. Find maximum responseEnd event among the filteredEvents + if (filteredEvents.length > 0) { + const maxResponseEndEvent = filteredEvents.reduce((prev, current) => + prev.responseEnd > current.responseEnd ? prev : current + ); + + const eventData: PaintEvent = { + version: '1.0.0', + startTime: maxResponseEndEvent.responseEnd, + duration: 0 + }; + + if (this.recordEvent) { + this.recordEvent(PERFORMANCE_FIRST_PAINT_EVENT_TYPE, eventData); + } + } + }; + + performancePaintEventHandler = (entryData: any): void => { + const eventData: PaintEvent = { + version: '1.0.0', + startTime: entryData.startTime, + duration: entryData.duration + }; + + let eventType = ''; + switch (entryData.name) { + case FIRST_PAINT: + eventType = PERFORMANCE_FIRST_PAINT_EVENT_TYPE; + break; + case FIRST_CONTENTFUL_PAINT: + eventType = PERFORMANCE_FIRST_CONTENTFUL_PAINT_EVENT_TYPE; + break; + } + if (this.recordEvent) { + this.recordEvent(eventType, eventData); + } + }; +} diff --git a/src/plugins/event-plugins/ResourcePlugin.ts b/src/plugins/event-plugins/ResourcePlugin.ts new file mode 100644 index 00000000..a4999737 --- /dev/null +++ b/src/plugins/event-plugins/ResourcePlugin.ts @@ -0,0 +1,191 @@ +import { RecordEvent, Plugin, PluginContext } from '../Plugin'; +import { + getResourceFileType, + getHost, + ResourceType, + shuffle +} from '../../utils/common-utils'; +import { ResourceEvent } from '../../events/resource-event'; +import { PERFORMANCE_RESOURCE_EVENT_TYPE } from '../utils/constant'; + +export const RESOURCE_EVENT_PLUGIN_ID = 'com.amazonaws.rum.resource'; + +const RESOURCE = 'resource'; +const LOAD = 'load'; + +export type ResourcePluginConfig = { + eventLimit: number; + recordAllTypes: ResourceType[]; + sampleTypes: ResourceType[]; +}; + +export const defaultRepConfig = { + eventLimit: 10, + recordAllTypes: [ResourceType.DOCUMENT, ResourceType.SCRIPT], + sampleTypes: [ + ResourceType.STYLESHEET, + ResourceType.IMAGE, + ResourceType.FONT, + ResourceType.OTHER + ] +}; + +/** + * This plugin records resource performance timing events generated during every page load/re-load. + */ +export class ResourcePlugin implements Plugin { + private pluginId: string; + private enabled: boolean; + private config: ResourcePluginConfig; + private recordEvent: RecordEvent | undefined; + + /** + * The data plane service endpoint. Resources from this endpoint will be + * ignored; i.e., this plugin will not generate resource performance events + * for them. + */ + private dataPlaneEndpoint: string; + + constructor(dataPlaneEndpoint) { + this.pluginId = RESOURCE_EVENT_PLUGIN_ID; + this.enabled = true; + this.dataPlaneEndpoint = dataPlaneEndpoint; + this.config = defaultRepConfig; + } + + load(context: PluginContext): void { + this.recordEvent = context.record; + window.addEventListener(LOAD, this.resourceEventListener); + } + + enable(): void { + if (this.enabled) { + return; + } + this.enabled = true; + window.addEventListener(LOAD, this.resourceEventListener); + } + + disable(): void { + if (!this.enabled) { + return; + } + this.enabled = false; + if (this.resourceEventListener) { + window.removeEventListener(LOAD, this.resourceEventListener); + } + } + + getPluginId(): string { + return this.pluginId; + } + + configure(config: ResourcePluginConfig): void { + this.config = config; + } + + resourceEventListener = (event: Event): void => { + const recordAll: PerformanceEntry[] = []; + const sample: PerformanceEntry[] = []; + let eventCount: number = 0; + + const resourceObserver = new PerformanceObserver((list) => { + list.getEntries() + .filter((e) => e.entryType === RESOURCE) + .forEach((event) => { + // Out of n resource events, x events are recorded using Observer API + const type: ResourceType = getResourceFileType(event.name); + if (this.config.recordAllTypes.includes(type)) { + recordAll.push(event); + } else if (this.config.sampleTypes.includes(type)) { + sample.push(event); + } + }); + }); + resourceObserver.observe({ + entryTypes: [RESOURCE] + }); + + // Remaining (n-x) resource events are recorded using getEntriesByType API. + // Note: IE11 browser does not support Performance Observer API. Handle the failure gracefully + const events = performance.getEntriesByType(RESOURCE); + if (events !== undefined && events.length > 0) { + events.forEach((event) => { + const type: ResourceType = getResourceFileType(event.name); + if (this.config.recordAllTypes.includes(type)) { + recordAll.push(event); + } else if (this.config.sampleTypes.includes(type)) { + sample.push(event); + } + }); + } + + // Record events for resources in recordAllTypes + shuffle(recordAll); + while (recordAll.length > 0 && eventCount < this.config.eventLimit) { + this.recordResourceEvent( + recordAll.pop() as PerformanceResourceTiming + ); + eventCount++; + } + + // Record events sampled from resources in sample + shuffle(sample); + while (sample.length > 0 && eventCount < this.config.eventLimit) { + this.recordResourceEvent(sample.pop() as PerformanceResourceTiming); + eventCount++; + } + }; + + recordResourceEvent = (entryData: PerformanceResourceTiming): void => { + if ( + this.recordEvent && + getHost(entryData.name) !== getHost(this.dataPlaneEndpoint) + ) { + const eventData: ResourceEvent = { + version: '1.0.0', + targetUrl: entryData.name, + initiatorType: entryData.initiatorType, + startTime: entryData.startTime, + redirectStart: entryData.redirectStart, + redirectTime: entryData.redirectEnd - entryData.redirectStart, + workerStart: entryData.workerStart, + workerTime: + entryData.workerStart > 0 + ? entryData.fetchStart - entryData.workerStart + : 0, + + fetchStart: entryData.fetchStart, + domainLookupStart: entryData.domainLookupStart, + dns: entryData.domainLookupEnd - entryData.domainLookupStart, + + nextHopProtocol: entryData.nextHopProtocol, + connectStart: entryData.connectStart, + connect: entryData.connectEnd - entryData.connectStart, + secureConnectionStart: entryData.secureConnectionStart, + tlsTime: + entryData.secureConnectionStart > 0 + ? entryData.connectEnd - entryData.secureConnectionStart + : 0, + + requestStart: entryData.requestStart, + timeToFirstByte: + entryData.responseStart - entryData.requestStart, + responseStart: entryData.responseStart, + responseTime: + entryData.responseStart > 0 + ? entryData.responseEnd - entryData.responseStart + : 0, + duration: entryData.duration, + headerSize: entryData.transferSize - entryData.encodedBodySize, + compressionRatio: + entryData.encodedBodySize > 0 + ? entryData.decodedBodySize / entryData.encodedBodySize + : 0, + transferSize: entryData.transferSize, + fileType: getResourceFileType(entryData.name) + }; + this.recordEvent(PERFORMANCE_RESOURCE_EVENT_TYPE, eventData); + } + }; +} diff --git a/src/plugins/event-plugins/WebVitalsPlugin.ts b/src/plugins/event-plugins/WebVitalsPlugin.ts new file mode 100644 index 00000000..ef9576eb --- /dev/null +++ b/src/plugins/event-plugins/WebVitalsPlugin.ts @@ -0,0 +1,52 @@ +import { RecordEvent, Plugin, PluginContext } from '../Plugin'; +import { LargestContentfulPaintEvent } from '../../events/largest-contentful-paint-event'; +import { FirstInputDelayEvent } from '../../events/first-input-delay-event'; +import { CumulativeLayoutShiftEvent } from '../../events/cumulative-layout-shift-event'; +import { getCLS, getFID, getLCP, Metric } from 'web-vitals'; +import { + LCP_EVENT_TYPE, + FID_EVENT_TYPE, + CLS_EVENT_TYPE +} from '../utils/constant'; + +export const WEB_VITAL_EVENT_PLUGIN_ID = 'com.amazonaws.rum.web-vitals'; + +export class WebVitalsPlugin implements Plugin { + private recordEvent: RecordEvent | undefined; + private pluginId: string; + + constructor() { + this.pluginId = WEB_VITAL_EVENT_PLUGIN_ID; + } + + load(context: PluginContext): void { + this.recordEvent = context.record; + getLCP((data) => this.getWebVitalData(data, LCP_EVENT_TYPE)); + getFID((data) => this.getWebVitalData(data, FID_EVENT_TYPE)); + getCLS((data) => this.getWebVitalData(data, CLS_EVENT_TYPE)); + } + + // tslint:disable-next-line:no-empty + enable(): void {} + + // tslint:disable-next-line:no-empty + disable(): void {} + + getPluginId(): string { + return this.pluginId; + } + + // tslint:disable-next-line:no-empty + configure(config: any): void {} + + getWebVitalData(webVitalData: Metric, eventType: string): void { + const webVitalEvent: + | LargestContentfulPaintEvent + | FirstInputDelayEvent + | CumulativeLayoutShiftEvent = { + version: '1.0.0', + value: webVitalData.value + }; + this.recordEvent(eventType, webVitalEvent); + } +} diff --git a/src/plugins/event-plugins/XhrPlugin.ts b/src/plugins/event-plugins/XhrPlugin.ts new file mode 100644 index 00000000..051b57f4 --- /dev/null +++ b/src/plugins/event-plugins/XhrPlugin.ts @@ -0,0 +1,327 @@ +import { Plugin, PluginContext } from '../Plugin'; +import { XRayTraceEvent } from '../../events/xray-trace-event'; +import { HttpEvent } from '../../events/http-event'; +import { MonkeyPatch, MonkeyPatched } from '../MonkeyPatched'; +import { + HttpPluginConfig, + defaultConfig, + epochTime, + createXRayTraceEvent, + getAmznTraceIdHeaderValue, + X_AMZN_TRACE_ID, + isUrlAllowed, + HttpPluginConfigWithDefaults +} from '../utils/http-utils'; +import { XhrError } from '../../errors/XhrError'; +import { HTTP_EVENT_TYPE, XRAY_TRACE_EVENT_TYPE } from '../utils/constant'; +import { errorEventToJsErrorEvent } from '../utils/js-error-utils'; + +type Send = () => void; +type Open = (method: string, url: string, async: boolean) => void; +type XhrDetails = { + method: string; + url: string; + async: boolean; + trace?: XRayTraceEvent; +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error + */ +type Error = { + message: string; + name: string; + fileName?: string; // non-standard Mozilla + lineNumber?: number; // non-standard Mozilla + columnNumber?: number; // non-standard Mozilla + stack?: string; // non-standard Mozilla +}; + +export const XHR_PLUGIN_ID = 'com.amazonaws.rum.xhr'; + +/** + * A plugin which initiates and records AWS X-Ray traces for XML HTTP requests (XMLHttpRequest). + * + * The XMLHttpRequest API is monkey patched using shimmer so all calls to XMLHttpRequest are intercepted. Only calls + * to URLs which are on the allowlist and are not on the denylist are traced and recorded. + * + * The XHR events we use (i.e., onload, onerror, onabort, ontimeout) are only + * supported by newer browsers. If we want to support older browsers we will + * need to detect older browsers and use the onreadystatechange event. + * + * For example, the following sequence events occur for each case: + * + * Case 1: Request succeeds events + * ------------------------------- + * readystatechange (state = 1, status = 0) + * loadstart + * readystatechange (state = 2, status = 200) + * readystatechange (state = 3, status = 200) + * readystatechange (state = 4, status = 200) + * load + * loadend + * + * Case 2: Request fails because of invalid domain or CORS failure + * ------------------------------- + * readystatechange (state = 1, status = 0) + * loadstart + * readystatechange (state = 4, status = 0) + * error + * loadend + * + * Case 3: Request fails because of timeout + * ------------------------------- + * readystatechange (state = 1, status = 0) + * loadstart + * readystatechange (state = 4, status = 0) + * timeout + * loadend + * + * Case 4: Request is aborted + * ------------------------------- + * readystatechange (state = 1, status = 0) + * loadstart + * readystatechange (state = 2, status = 200) + * readystatechange (state = 3, status = 200) + * readystatechange (state = 4, status = 0) + * abort + * loadend + * + * See + * - https://xhr.spec.whatwg.org/#event-handlers. + * - https://xhr.spec.whatwg.org/#events + */ +export class XhrPlugin extends MonkeyPatched implements Plugin { + private pluginId: string; + private config: HttpPluginConfigWithDefaults; + private xhrMap: Map; + private context: PluginContext; + + constructor(config?: HttpPluginConfig) { + super(); + this.pluginId = XHR_PLUGIN_ID; + this.config = { ...defaultConfig, ...config }; + this.xhrMap = new Map(); + } + + public load(context: PluginContext): void { + this.context = context; + this.enable(); + } + + public getPluginId(): string { + return this.pluginId; + } + + public configure(config: HttpPluginConfig): void { + this.config = { ...this.config, ...config }; + } + + protected patches(): MonkeyPatch[] { + return [ + { + nodule: XMLHttpRequest.prototype, + name: 'send', + wrapper: this.sendWrapper + }, + { + nodule: XMLHttpRequest.prototype, + name: 'open', + wrapper: this.openWrapper + } + ]; + } + + private isTracingEnabled = () => { + return this.config.trace; + }; + + private isSessionRecorded = () => { + return this.context.getSession().record; + }; + + private handleXhrLoadEvent = (e: Event) => { + const xhr: XMLHttpRequest = e.target as XMLHttpRequest; + const xhrDetails: XhrDetails = this.xhrMap.get(xhr); + if (xhrDetails) { + const endTime = epochTime(); + xhrDetails.trace.end_time = endTime; + xhrDetails.trace.http.response = { + status: xhr.status + }; + this.recordTraceEvent(xhrDetails.trace); + this.recordHttpEventWithResponse(xhrDetails, xhr); + } + }; + + private handleXhrErrorEvent = (e: Event) => { + const xhr: XMLHttpRequest = e.target as XMLHttpRequest; + const xhrDetails: XhrDetails = this.xhrMap.get(xhr); + const errorName: string = 'XMLHttpRequest error'; + const errorMessage: string = xhr.statusText + ? xhr.status.toString() + ': ' + xhr.statusText + : xhr.status.toString(); + if (xhrDetails) { + const endTime = epochTime(); + xhrDetails.trace.end_time = endTime; + xhrDetails.trace.error = true; + xhrDetails.trace.cause = { + exceptions: [ + { + type: errorName, + message: errorMessage + } + ] + }; + this.recordTraceEvent(xhrDetails.trace); + this.recordHttpEventWithError( + xhrDetails, + new XhrError(errorMessage) + ); + } + }; + + private handleXhrAbortEvent = (e: Event) => { + const xhr: XMLHttpRequest = e.target as XMLHttpRequest; + const xhrDetails: XhrDetails = this.xhrMap.get(xhr); + const errorName: string = 'XMLHttpRequest abort'; + if (xhrDetails) { + const endTime = epochTime(); + xhrDetails.trace.end_time = endTime; + xhrDetails.trace.error = true; + xhrDetails.trace.cause = { + exceptions: [ + { + type: errorName + } + ] + }; + this.recordTraceEvent(xhrDetails.trace); + this.recordHttpEventWithError(xhrDetails, errorName); + } + }; + + private handleXhrTimeoutEvent = (e: Event) => { + const xhr: XMLHttpRequest = e.target as XMLHttpRequest; + const xhrDetails: XhrDetails = this.xhrMap.get(xhr); + const errorName: string = 'XMLHttpRequest timeout'; + if (xhrDetails) { + const endTime = epochTime(); + xhrDetails.trace.end_time = endTime; + xhrDetails.trace.error = true; + xhrDetails.trace.cause = { + exceptions: [ + { + type: errorName + } + ] + }; + this.recordTraceEvent(xhrDetails.trace); + this.recordHttpEventWithError(xhrDetails, errorName); + } + }; + + private statusOk(status: number) { + return status >= 200 && status < 300; + } + + private recordHttpEventWithResponse( + xhrDetails: XhrDetails, + xhr: XMLHttpRequest + ) { + if (this.config.recordAllRequests || !this.statusOk(xhr.status)) { + this.context.record(HTTP_EVENT_TYPE, { + version: '1.0.0', + request: { method: xhrDetails.method, url: xhrDetails.url }, + response: { status: xhr.status, statusText: xhr.statusText } + }); + } + } + + private recordHttpEventWithError( + xhrDetails: XhrDetails, + error: Error | string | number | boolean | undefined | null + ) { + const httpEvent: HttpEvent = { + version: '1.0.0', + request: { method: xhrDetails.method, url: xhrDetails.url } + }; + httpEvent.error = errorEventToJsErrorEvent( + { + type: 'error', + error + } as ErrorEvent, + this.config.stackTraceLength + ); + this.context.record(HTTP_EVENT_TYPE, httpEvent); + } + + private recordTraceEvent(trace: XRayTraceEvent) { + if (this.isTracingEnabled() && this.isSessionRecorded()) { + this.context.record(XRAY_TRACE_EVENT_TYPE, trace); + } + } + + private initializeTrace = (xhrDetails: XhrDetails) => { + const startTime = epochTime(); + xhrDetails.trace = createXRayTraceEvent( + this.config.logicalServiceName, + startTime, + { + request: { + url: xhrDetails.url, + method: xhrDetails.method, + traced: true + } + } + ); + }; + + private sendWrapper = (): ((original: Send) => Send) => { + const self = this; + return (original: Send): Send => { + return function (this: XMLHttpRequest): void { + const xhrDetails: XhrDetails = self.xhrMap.get(this); + if (xhrDetails) { + this.addEventListener('load', self.handleXhrLoadEvent); + this.addEventListener('error', self.handleXhrErrorEvent); + this.addEventListener('abort', self.handleXhrAbortEvent); + this.addEventListener( + 'timeout', + self.handleXhrTimeoutEvent + ); + + self.initializeTrace(xhrDetails); + + if (self.isTracingEnabled() && self.isSessionRecorded()) { + this.setRequestHeader( + X_AMZN_TRACE_ID, + getAmznTraceIdHeaderValue( + xhrDetails.trace.trace_id, + xhrDetails.trace.id + ) + ); + } + } + return original.apply(this, arguments); + }; + }; + }; + + private openWrapper = (): ((original: Open) => Open) => { + const self = this; + return (original: Open): Open => { + return function ( + this: XMLHttpRequest, + method: string, + url: string, + async: boolean + ): void { + if (isUrlAllowed(url, self.config)) { + self.xhrMap.set(this, { url, method, async }); + } + return original.apply(this, arguments); + }; + }; + }; +} diff --git a/src/plugins/event-plugins/__integ__/DomEventPlugin.test.ts b/src/plugins/event-plugins/__integ__/DomEventPlugin.test.ts new file mode 100644 index 00000000..05e437c1 --- /dev/null +++ b/src/plugins/event-plugins/__integ__/DomEventPlugin.test.ts @@ -0,0 +1,191 @@ +import { SESSION_START_EVENT_TYPE } from '../../../sessions/SessionManager'; +import { Selector } from 'testcafe'; +import { REQUEST_BODY } from '../../../test-utils/integ-test-utils'; + +const recordDocumentClicks: Selector = Selector(`#recordDocumentClicks`); +const recordButton1Clicks: Selector = Selector(`#recordButton1Clicks`); +const doNotRecordClicks: Selector = Selector(`#doNotRecordClicks`); +const disable: Selector = Selector(`#disable`); +const enable: Selector = Selector(`#enable`); + +const button1: Selector = Selector(`#button1`); +const link1: Selector = Selector(`a`); + +const dispatch: Selector = Selector(`#dispatch`); +const clear: Selector = Selector(`#clearRequestResponse`); + +fixture('DomEventPlugin').page('http://localhost:8080/dom_event.html'); + +const removeUnwantedEvents = (json: any) => { + const newEventsList = []; + for (const event of json.batch.events) { + if (/(dispatch)/.test(event.details)) { + // Skip + } else if (/(session_start_event)/.test(event.type)) { + // Skip + } else if (/(page_view_event)/.test(event.type)) { + // Skip + } else { + newEventsList.push(event); + } + } + + json.batch.events = newEventsList; + return json; +}; + +test('when document click events configured then button click is recorded', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t + .wait(300) + .click(recordDocumentClicks) + .click(button1) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const json = removeUnwantedEvents( + JSON.parse(await REQUEST_BODY.textContent) + ); + const eventType = json.batch.events[0].type; + const eventDetails = JSON.parse(json.batch.events[0].details); + + await t + .expect(eventType) + .eql('com.amazon.rum.dom_event') + .expect(eventDetails) + .contains({ + event: 'click', + elementId: 'button1' + }); +}); + +test('when element without an id is clicked then node type is recorded', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t + .wait(300) + .click(recordDocumentClicks) + .click(link1) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const json = removeUnwantedEvents( + JSON.parse(await REQUEST_BODY.textContent) + ); + const eventType = json.batch.events[0].type; + const eventDetails = JSON.parse(json.batch.events[0].details); + + await t + .expect(eventType) + .eql('com.amazon.rum.dom_event') + .expect(eventDetails) + .contains({ + event: 'click', + elementId: 'A' + }); +}); + +test('when element id click event configured then button click is recorded', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t + .wait(300) + .click(recordButton1Clicks) + .click(button1) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const json = removeUnwantedEvents( + JSON.parse(await REQUEST_BODY.textContent) + ); + const eventType = json.batch.events[0].type; + const eventDetails = JSON.parse(json.batch.events[0].details); + + await t + .expect(eventType) + .eql('com.amazon.rum.dom_event') + .expect(eventDetails) + .contains({ + event: 'click', + elementId: 'button1' + }); +}); + +test('when client is disabled prior to config then button click is not recorded', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t + .wait(300) + .click(disable) + .click(recordButton1Clicks) + .click(button1) + .click(enable) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const json = JSON.parse(await REQUEST_BODY.textContent); + const eventType = json.batch.events[0].type; + + await t + .expect(json.batch.events.length) + .eql(2) + .expect(eventType) + .eql(SESSION_START_EVENT_TYPE); +}); + +test('when client is disabled after config then button click is not recorded', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t + .wait(300) + .click(recordButton1Clicks) + .click(disable) + .click(button1) + .click(enable) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const json = JSON.parse(await REQUEST_BODY.textContent); + const eventType = json.batch.events[0].type; + + await t + .expect(json.batch.events.length) + .eql(2) + .expect(eventType) + .eql(SESSION_START_EVENT_TYPE); +}); + +test('when client is disabled and enabled then button click is recorded', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t + .wait(300) + .click(recordButton1Clicks) + .click(disable) + .click(enable) + .click(button1) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const json = removeUnwantedEvents( + JSON.parse(await REQUEST_BODY.textContent) + ); + const eventType = json.batch.events[0].type; + const eventDetails = JSON.parse(json.batch.events[0].details); + + await t + .expect(eventType) + .eql('com.amazon.rum.dom_event') + .expect(eventDetails) + .contains({ + event: 'click', + elementId: 'button1' + }); +}); diff --git a/src/plugins/event-plugins/__integ__/FetchPlugin.test.ts b/src/plugins/event-plugins/__integ__/FetchPlugin.test.ts new file mode 100644 index 00000000..29d88da8 --- /dev/null +++ b/src/plugins/event-plugins/__integ__/FetchPlugin.test.ts @@ -0,0 +1,64 @@ +import { Selector } from 'testcafe'; +import { REQUEST_BODY } from '../../../test-utils/integ-test-utils'; +import { XRAY_TRACE_EVENT_TYPE, HTTP_EVENT_TYPE } from '../../utils/constant'; + +const sendFetchRequest: Selector = Selector(`#sendFetchRequest`); +const sendDataPlaneRequest: Selector = Selector(`#sendDataPlaneRequest`); +const dispatch: Selector = Selector(`#dispatch`); +const clearRequestResponse: Selector = Selector(`#clearRequestResponse`); + +fixture('X-Ray Fetch Plugin').page( + 'http://localhost:8080/http_fetch_event.html' +); + +test('when fetch is called then a trace is recorded', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t + .wait(300) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch') + .click(clearRequestResponse) + .click(sendFetchRequest) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const json = JSON.parse(await REQUEST_BODY.textContent); + const eventType = json.batch.events[0].type; + const eventDetails = JSON.parse(json.batch.events[0].details); + + await t + .expect(eventType) + .eql(XRAY_TRACE_EVENT_TYPE) + .expect(eventDetails.name) + .eql('sample.rum.aws.amazon.com'); +}); + +test('when fetch is called then an http event is recorded', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t + .wait(300) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch') + .click(clearRequestResponse) + .click(sendFetchRequest) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const json = JSON.parse(await REQUEST_BODY.textContent); + const eventType = json.batch.events[1].type; + const eventDetails = JSON.parse(json.batch.events[1].details); + + await t + .expect(eventType) + .eql(HTTP_EVENT_TYPE) + .expect(eventDetails.request.url) + .eql('https://aws.amazon.com') + .expect(eventDetails.response.status) + .eql(200); +}); diff --git a/src/plugins/event-plugins/__integ__/JsErrorPlugin.test.ts b/src/plugins/event-plugins/__integ__/JsErrorPlugin.test.ts new file mode 100644 index 00000000..6dade72e --- /dev/null +++ b/src/plugins/event-plugins/__integ__/JsErrorPlugin.test.ts @@ -0,0 +1,146 @@ +import { Selector } from 'testcafe'; +import { REQUEST_BODY } from '../../../test-utils/integ-test-utils'; +import { JS_ERROR_EVENT_TYPE } from '../../utils/constant'; + +const triggerTypeError: Selector = Selector(`#triggerTypeError`); +const throwErrorString: Selector = Selector(`#throwErrorString`); +const recordStackTrace: Selector = Selector(`#recordStackTrace`); +const recordCaughtError: Selector = Selector(`#recordCaughtError`); + +const dispatch: Selector = Selector(`#dispatch`); + +fixture('JSErrorEvent Plugin').page( + 'http://localhost:8080/js_error_event.html' +); + +const removeUnwantedEvents = (json: any) => { + const newEventsList = []; + for (const event of json.batch.events) { + if (/(dispatch)/.test(event.details)) { + // Skip + } else if (/(session_start_event)/.test(event.type)) { + // Skip + } else if (/(page_view_event)/.test(event.type)) { + // Skip + } else { + newEventsList.push(event); + } + } + + json.batch.events = newEventsList; + return json; +}; + +test('when a TypeError is thrown then name and message are recorded', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t + .wait(300) + .click(triggerTypeError) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const json = removeUnwantedEvents( + JSON.parse(await REQUEST_BODY.textContent) + ); + const eventType = json.batch.events[0].type; + const eventDetails = JSON.parse(json.batch.events[0].details); + + await t + .expect(eventType) + .eql(JS_ERROR_EVENT_TYPE) + .expect(eventDetails.type) + .contains('TypeError') + .expect(eventDetails.message) + .match(/(undefined|null)/) + .expect(eventDetails.filename) + .match(/js_error_event.html/) + .expect(eventDetails.lineno) + .match(/\d+/) + .expect(eventDetails.colno) + .match(/\d+/); +}); + +test('when stack trace is > 0 then stack trace is recorded', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t + .wait(300) + .click(recordStackTrace) + .click(triggerTypeError) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const json = removeUnwantedEvents( + JSON.parse(await REQUEST_BODY.textContent) + ); + const eventType = json.batch.events[0].type; + const eventDetails = JSON.parse(json.batch.events[0].details); + + await t + .expect(eventType) + .eql(JS_ERROR_EVENT_TYPE) + .expect(eventDetails.stack) + .contains('triggerTypeError'); +}); + +test('when a string is thrown then name and message are recorded', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t + .wait(300) + .click(throwErrorString) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const json = removeUnwantedEvents( + JSON.parse(await REQUEST_BODY.textContent) + ); + const eventType = json.batch.events[0].type; + const eventDetails = JSON.parse(json.batch.events[0].details); + + await t + .expect(eventType) + .eql(JS_ERROR_EVENT_TYPE) + .expect(eventDetails.type) + .contains('thrown string') + .expect(eventDetails.message) + .contains('thrown string') + .expect(eventDetails.filename) + .match(/js_error_event.html/) + .expect(eventDetails.lineno) + .match(/\d+/) + .expect(eventDetails.colno) + .match(/\d+/); +}); + +test('when the application records a caught error then the plugin records the error', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t + .wait(300) + .click(recordCaughtError) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const events = JSON.parse( + await REQUEST_BODY.textContent + ).batch.events.filter((e) => e.type === JS_ERROR_EVENT_TYPE); + + const eventType = events[0].type; + const eventDetails = JSON.parse(events[0].details); + + await t + .expect(events.length) + .eql(1) + .expect(eventType) + .eql(JS_ERROR_EVENT_TYPE) + .expect(eventDetails.type) + .contains('Error') + .expect(eventDetails.message) + .contains('My error message'); +}); diff --git a/src/plugins/event-plugins/__integ__/PerformancePlugin.test.ts b/src/plugins/event-plugins/__integ__/PerformancePlugin.test.ts new file mode 100644 index 00000000..6ccab17d --- /dev/null +++ b/src/plugins/event-plugins/__integ__/PerformancePlugin.test.ts @@ -0,0 +1,288 @@ +import { + STATUS_202, + DISPATCH_COMMAND, + COMMAND, + PAYLOAD, + SUBMIT, + REQUEST_BODY, + RESPONSE_STATUS, + ID, + TIMESTAMP +} from '../../../test-utils/integ-test-utils'; +import { + PERFORMANCE_NAVIGATION_EVENT_TYPE, + PERFORMANCE_FIRST_CONTENTFUL_PAINT_EVENT_TYPE, + PERFORMANCE_FIRST_PAINT_EVENT_TYPE, + PERFORMANCE_RESOURCE_EVENT_TYPE +} from '../../utils/constant'; + +const TARGET_URL = 'targetUrl'; +const INITIATOR_TYPE = 'initiatorType'; +const NAVIGATION_TYPE = 'navigationType'; +const START_TIME = 'startTime'; +const UNLOAD_EVENT_START = 'unloadEventStart'; +const PROMPT_FOR_UNLOAD = 'promptForUnload'; +const REDIRECT_COUNT = 'redirectCount'; +const REDIRECT_START = 'redirectStart'; +const REDIRECT_TIME = 'redirectTime'; +const WORKER_START = 'workerStart'; +const WORKER_TIME = 'workerTime'; +const FETCH_START = 'fetchStart'; +const DOMAIN_LOOKUP_START = 'domainLookupStart'; +const DNS = 'dns'; +const NEXT_HOP_PROTOCOL = 'nextHopProtocol'; +const CONNECT_START = 'connectStart'; +const CONNECT = 'connect'; +const SECURE_CONNECTION_START = 'secureConnectionStart'; +const TLS_TIME = 'tlsTime'; +const REQUEST_START = 'requestStart'; +const TIME_TO_FIRST_BYTE = 'timeToFirstByte'; +const RESPONSE_START = 'responseStart'; +const RESPONSE_TIME = 'responseTime'; +const DOM_INTERACTIVE = 'domInteractive'; +const DOM_CONTENT_LOADED_EVENT_START = 'domContentLoadedEventStart'; +const DOM_CONTENT_LOADED = 'domContentLoaded'; +const DOM_COMPLETE = 'domComplete'; +const DOM_PROCESSING_TIME = 'domProcessingTime'; +const LOAD_EVENT_START = 'loadEventStart'; +const LOAD_EVENT_TIME = 'loadEventTime'; +const DURATION = 'duration'; +const HEADER_SIZE = 'headerSize'; +const TRANSFER_SIZE = 'transferSize'; +const COMPRESSION_RATIO = 'compressionRatio'; +const FILE_TYPE = 'fileType'; +const SAFARI = 'Safari'; +const FIREFOX = 'Firefox'; + +fixture('PerformanceEvent Plugin').page('http://localhost:8080/'); + +test('PerformanceEvent records navigation event', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t.wait(300); + + await t + .typeText(COMMAND, DISPATCH_COMMAND, { replace: true }) + .click(PAYLOAD) + .pressKey('ctrl+a delete') + .click(SUBMIT); + + await t.wait(300); + + const isBrowserSafari = + (await REQUEST_BODY.textContent).indexOf(SAFARI) > -1; + + await t + .expect(REQUEST_BODY.textContent) + .contains(PERFORMANCE_NAVIGATION_EVENT_TYPE) + .expect(REQUEST_BODY.textContent) + .contains(ID) + .expect(REQUEST_BODY.textContent) + .contains(TIMESTAMP) + + .expect(REQUEST_BODY.textContent) + .contains(INITIATOR_TYPE) + .expect(REQUEST_BODY.textContent) + .contains(START_TIME) + .expect(REQUEST_BODY.textContent) + .contains(UNLOAD_EVENT_START) + .expect(REQUEST_BODY.textContent) + .contains(PROMPT_FOR_UNLOAD) + .expect(REQUEST_BODY.textContent) + .contains(REDIRECT_START) + .expect(REQUEST_BODY.textContent) + .contains(REDIRECT_TIME) + + .expect(REQUEST_BODY.textContent) + .contains(FETCH_START) + .expect(REQUEST_BODY.textContent) + .contains(DOMAIN_LOOKUP_START) + .expect(REQUEST_BODY.textContent) + .contains(DNS) + + .expect(REQUEST_BODY.textContent) + .contains(CONNECT_START) + .expect(REQUEST_BODY.textContent) + .contains(CONNECT) + .expect(REQUEST_BODY.textContent) + .contains(SECURE_CONNECTION_START) + .expect(REQUEST_BODY.textContent) + .contains(TLS_TIME) + .expect(REQUEST_BODY.textContent) + .contains(REQUEST_START) + .expect(REQUEST_BODY.textContent) + .contains(TIME_TO_FIRST_BYTE) + .expect(REQUEST_BODY.textContent) + .contains(RESPONSE_START) + .expect(REQUEST_BODY.textContent) + .contains(RESPONSE_TIME) + .expect(REQUEST_BODY.textContent) + .contains(DOM_INTERACTIVE) + .expect(REQUEST_BODY.textContent) + .contains(DOM_CONTENT_LOADED_EVENT_START) + .expect(REQUEST_BODY.textContent) + .contains(DOM_CONTENT_LOADED) + .expect(REQUEST_BODY.textContent) + .contains(DOM_COMPLETE) + .expect(REQUEST_BODY.textContent) + .contains(DOM_PROCESSING_TIME) + .expect(REQUEST_BODY.textContent) + .contains(LOAD_EVENT_START) + .expect(REQUEST_BODY.textContent) + .contains(LOAD_EVENT_TIME) + .expect(REQUEST_BODY.textContent) + .contains(DURATION) + + .expect(RESPONSE_STATUS.textContent) + .eql(STATUS_202.toString()); + + /** + * Deprecated Timing Level1 used for Safari browser do not contain following attributes + * https://nicj.net/navigationtiming-in-practice/ + */ + if (!isBrowserSafari) { + await t + .expect(REQUEST_BODY.textContent) + .contains(TARGET_URL) + .expect(REQUEST_BODY.textContent) + .contains(REDIRECT_COUNT) + .expect(REQUEST_BODY.textContent) + .contains(NAVIGATION_TYPE) + .expect(REQUEST_BODY.textContent) + .contains(WORKER_START) + .expect(REQUEST_BODY.textContent) + .contains(WORKER_TIME) + .expect(REQUEST_BODY.textContent) + .contains(NEXT_HOP_PROTOCOL) + .expect(REQUEST_BODY.textContent) + .contains(HEADER_SIZE) + .expect(REQUEST_BODY.textContent) + .contains(TRANSFER_SIZE) + .expect(REQUEST_BODY.textContent) + .contains(COMPRESSION_RATIO); + } +}); + +test('PerformanceEvent records paint event', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t.wait(300); + + await t + .typeText(COMMAND, DISPATCH_COMMAND, { replace: true }) + .click(PAYLOAD) + .pressKey('ctrl+a delete') + .click(SUBMIT); + + await t.wait(300); + + const isBrowserFirefox = + (await REQUEST_BODY.textContent).indexOf(FIREFOX) > -1; + + /** + * Firefox and Safari browsers do not support First Contentful Paint API + */ + if (!isBrowserFirefox) { + await t + .expect(REQUEST_BODY.textContent) + .contains(PERFORMANCE_FIRST_CONTENTFUL_PAINT_EVENT_TYPE); + } + + await t + .expect(REQUEST_BODY.textContent) + .contains(ID) + .expect(REQUEST_BODY.textContent) + .contains(TIMESTAMP) + + .expect(REQUEST_BODY.textContent) + .contains(PERFORMANCE_FIRST_PAINT_EVENT_TYPE) + .expect(REQUEST_BODY.textContent) + .contains(START_TIME) + .expect(REQUEST_BODY.textContent) + .contains(DURATION) + + .expect(RESPONSE_STATUS.textContent) + .eql(STATUS_202.toString()); +}); + +test('PerformanceEvent records resource event', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t.wait(300); + + await t + .typeText(COMMAND, DISPATCH_COMMAND, { replace: true }) + .click(PAYLOAD) + .pressKey('ctrl+a delete') + .click(SUBMIT); + + await t.wait(300); + + const isBrowserSafari = + (await REQUEST_BODY.textContent).indexOf(SAFARI) > -1; + // expect http request body contains click event type + // expect http response with mock status code 202 + await t + .expect(REQUEST_BODY.textContent) + .contains(PERFORMANCE_RESOURCE_EVENT_TYPE) + .expect(REQUEST_BODY.textContent) + .contains(ID) + .expect(REQUEST_BODY.textContent) + .contains(TIMESTAMP) + + .expect(REQUEST_BODY.textContent) + .contains(TARGET_URL) + .expect(REQUEST_BODY.textContent) + .contains(INITIATOR_TYPE) + .expect(REQUEST_BODY.textContent) + .contains(START_TIME) + .expect(REQUEST_BODY.textContent) + .contains(REDIRECT_START) + .expect(REQUEST_BODY.textContent) + .contains(REDIRECT_TIME) + .expect(REQUEST_BODY.textContent) + .contains(WORKER_START) + .expect(REQUEST_BODY.textContent) + .contains(WORKER_TIME) + .expect(REQUEST_BODY.textContent) + .contains(FETCH_START) + .expect(REQUEST_BODY.textContent) + .contains(DOMAIN_LOOKUP_START) + .expect(REQUEST_BODY.textContent) + .contains(DNS) + .expect(REQUEST_BODY.textContent) + .contains(NEXT_HOP_PROTOCOL) + .expect(REQUEST_BODY.textContent) + .contains(CONNECT_START) + .expect(REQUEST_BODY.textContent) + .contains(CONNECT) + .expect(REQUEST_BODY.textContent) + .contains(SECURE_CONNECTION_START) + .expect(REQUEST_BODY.textContent) + .contains(TLS_TIME) + .expect(REQUEST_BODY.textContent) + .contains(REQUEST_START) + .expect(REQUEST_BODY.textContent) + .contains(TIME_TO_FIRST_BYTE) + .expect(REQUEST_BODY.textContent) + .contains(RESPONSE_START) + .expect(REQUEST_BODY.textContent) + .contains(RESPONSE_TIME) + .expect(REQUEST_BODY.textContent) + .contains(DURATION) + .expect(REQUEST_BODY.textContent) + .contains(HEADER_SIZE) + .expect(REQUEST_BODY.textContent) + .contains(COMPRESSION_RATIO) + .expect(REQUEST_BODY.textContent) + .contains(FILE_TYPE) + .expect(RESPONSE_STATUS.textContent) + .eql(STATUS_202.toString()); + + /** + * Safari browser does not support transferSize from Resource API + */ + if (!isBrowserSafari) { + await t.expect(REQUEST_BODY.textContent).contains(TRANSFER_SIZE); + } +}); diff --git a/src/plugins/event-plugins/__integ__/WebVitalsPlugin.test.ts b/src/plugins/event-plugins/__integ__/WebVitalsPlugin.test.ts new file mode 100644 index 00000000..34e7d429 --- /dev/null +++ b/src/plugins/event-plugins/__integ__/WebVitalsPlugin.test.ts @@ -0,0 +1,68 @@ +import { + STATUS_202, + REQUEST_BODY, + RESPONSE_STATUS +} from '../../../test-utils/integ-test-utils'; +import { Selector } from 'testcafe'; +import { CLS_EVENT_TYPE, LCP_EVENT_TYPE } from '../../utils/constant'; + +const testButton: Selector = Selector(`#testButton`); +const makePageHidden: Selector = Selector(`#makePageHidden`); + +fixture('WebVitalEvent Plugin').page( + 'http://localhost:8080/web_vital_event.html' +); + +// According to https://github.com/GoogleChrome/web-vitals, "FID is not reported if the user never interacts with the page." +// It doesn't seem like TestCafe actions are registered as user interactions, so cannot test FID + +const removeUnwantedEvents = (json: any) => { + const newEventsList = []; + for (const event of json.batch.events) { + if (/(dispatch)/.test(event.details)) { + // Skip + } else if (/(session_start_event)/.test(event.type)) { + // Skip + } else if (/(page_view_event)/.test(event.type)) { + // Skip + } else { + newEventsList.push(event); + } + } + + json.batch.events = newEventsList; + return json; +}; + +test('WebVitalEvent records lcp and cls events', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t.wait(300); + + await t + // Interact with page to trigger lcp event + .click(testButton) + .click(makePageHidden) + .expect(RESPONSE_STATUS.textContent) + .eql(STATUS_202.toString()) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const json = removeUnwantedEvents( + JSON.parse(await REQUEST_BODY.textContent) + ); + const eventType1 = json.batch.events[0].type; + const eventDetails1 = JSON.parse(json.batch.events[0].details); + const eventType2 = json.batch.events[1].type; + const eventDetails2 = JSON.parse(json.batch.events[1].details); + + await t + .expect(eventType1) + .eql(LCP_EVENT_TYPE) + .expect(eventDetails1.value) + .typeOf('number') + .expect(eventType2) + .eql(CLS_EVENT_TYPE) + .expect(eventDetails2.value) + .typeOf('number'); +}); diff --git a/src/plugins/event-plugins/__integ__/XhrPlugin.test.ts b/src/plugins/event-plugins/__integ__/XhrPlugin.test.ts new file mode 100644 index 00000000..01d98968 --- /dev/null +++ b/src/plugins/event-plugins/__integ__/XhrPlugin.test.ts @@ -0,0 +1,96 @@ +import { Selector } from 'testcafe'; +import { REQUEST_BODY } from '../../../test-utils/integ-test-utils'; +import { HTTP_EVENT_TYPE, XRAY_TRACE_EVENT_TYPE } from '../../utils/constant'; + +const sendAsyncXhrRequest: Selector = Selector(`#sendAsyncXhrRequest`); +const sendSyncXhrRequest: Selector = Selector(`#sendSyncXhrRequest`); +const dispatch: Selector = Selector(`#dispatch`); +const clearRequestResponse: Selector = Selector(`#clearRequestResponse`); + +fixture('X-Ray XMLHttpRequest Plugin').page( + 'http://localhost:8080/http_xhr_event.html' +); + +test('when async XMLHttpRequest is called then a trace is recorded', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t + .wait(300) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch') + .click(clearRequestResponse) + .click(sendAsyncXhrRequest) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const events = JSON.parse( + await REQUEST_BODY.textContent + ).batch.events.filter((e) => e.type === XRAY_TRACE_EVENT_TYPE); + + const eventType = events[0].type; + const eventDetails = JSON.parse(events[0].details); + + await t + .expect(eventType) + .eql(XRAY_TRACE_EVENT_TYPE) + .expect(eventDetails.name) + .eql('sample.rum.aws.amazon.com'); +}); + +test('when sync XMLHttpRequest is called then a trace is recorded', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t + .wait(300) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch') + .click(clearRequestResponse) + .click(sendSyncXhrRequest) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const events = JSON.parse( + await REQUEST_BODY.textContent + ).batch.events.filter((e) => e.type === XRAY_TRACE_EVENT_TYPE); + + const eventType = events[0].type; + const eventDetails = JSON.parse(events[0].details); + + await t + .expect(eventType) + .eql(XRAY_TRACE_EVENT_TYPE) + .expect(eventDetails.name) + .eql('sample.rum.aws.amazon.com'); +}); + +test('when sync XMLHttpRequest is called then an http event is recorded', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t + .wait(300) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch') + .click(clearRequestResponse) + .click(sendSyncXhrRequest) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const events = JSON.parse( + await REQUEST_BODY.textContent + ).batch.events.filter((e) => e.type === HTTP_EVENT_TYPE); + + const eventType = events[0].type; + const eventDetails = JSON.parse(events[0].details); + + await t + .expect(eventType) + .eql(HTTP_EVENT_TYPE) + .expect(eventDetails.request.method) + .eql('GET'); +}); diff --git a/src/plugins/event-plugins/__nightwatch__/PageViewPlugin.test.js b/src/plugins/event-plugins/__nightwatch__/PageViewPlugin.test.js new file mode 100644 index 00000000..64efb289 --- /dev/null +++ b/src/plugins/event-plugins/__nightwatch__/PageViewPlugin.test.js @@ -0,0 +1,86 @@ +const pushStateOne = '#pushStateOneToHistory'; +const pushStateTwo = '#pushStateTwoToHistory'; +const back = '#back'; +const dispatch = '#dispatch'; +const clear = '#clearRequestResponse'; +const parse = '#clean-data'; + +/** + * TestCafe and Cypress drive the browser by injecting javascript into the page. + * This involves monkey patching the window.history APIs. This somehow prevents + * the plugin from monkey patching the window.history API. To solve this problem, + * we use nightwatch instead of TestCafe. Nightwatch uses the W3C WebDriver + * protocol and therefore does not interfere with monkey patching. + */ +describe('Page Event History Patch Plugin', function () { + test('when window.history.pushState() is called then a page view event is recorded', async function (browser) { + browser + .url('http://localhost:8080/page_event.html') + .pause(300) + .waitForElementVisible('body') + .click(pushStateOne) + .click(pushStateTwo) + .click(dispatch); + + const request_body = JSON.parse( + (await browser.getText('#request_body')).value + ); + + const pages = request_body.batch.events + .filter((e) => e.type === 'com.amazon.rum.page_view_event') + .map((e) => JSON.parse(e.details).pageId); + + browser.assert.equal( + pages.includes('/page_event.html'), + true, + '/page_event.html was recorded' + ); + browser.assert.equal( + pages.includes('/page_view_one'), + true, + '/page_view_one was recorded' + ); + browser.assert.equal( + pages.includes('/page_view_two'), + true, + '/page_view_two was recorded' + ); + + browser.end(); + }); + + test('when window.history.back() is called then a page view event is recorded', async function (browser) { + browser + .url('http://localhost:8080/page_event.html') + .pause(300) + .waitForElementVisible('body') + .click(pushStateOne) + .click(pushStateTwo) + .click(dispatch) + .click(clear) + .click(back) + .click(back) + .click(dispatch); + + const request_body = JSON.parse( + (await browser.getText('#request_body')).value + ); + + const pages = request_body.batch.events + .filter((e) => e.type === 'com.amazon.rum.page_view_event') + .map((e) => JSON.parse(e.details).pageId); + + browser.assert.equal( + pages.includes('/page_event.html'), + true, + '/page_event.html was recorded' + ); + browser.assert.equal( + pages.includes('/page_view_one'), + true, + '/page_view_one was recorded' + ); + + browser.end(); + }); +}); diff --git a/src/plugins/event-plugins/__tests__/DomEventPlugin.test.ts b/src/plugins/event-plugins/__tests__/DomEventPlugin.test.ts new file mode 100644 index 00000000..afe09e41 --- /dev/null +++ b/src/plugins/event-plugins/__tests__/DomEventPlugin.test.ts @@ -0,0 +1,105 @@ +import { DomEventPlugin } from '../DomEventPlugin'; +import { context, record } from '../../../test-utils/test-utils'; +import { DOM_EVENT_TYPE } from '../../utils/constant'; + +describe('DomEventPlugin tests', () => { + beforeEach(() => { + record.mockClear(); + }); + + test('DomEventPlugin records events by default', async () => { + // Init + document.body.innerHTML = ''; + const plugin: JsErrorPlugin = new JsErrorPlugin(); + + // Run + plugin.load(context); + // @ts-ignore + document.getElementById('createJSError').click(); + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(1); + // @ts-ignore + expect(record.mock.calls[0][0]).toEqual(JS_ERROR_EVENT_TYPE); + // @ts-ignore + expect(record.mock.calls[0][1]).toMatchObject( + expect.objectContaining({ + version: '1.0.0', + type: 'TypeError', + message: "Cannot read property 'foo' of null", + stack: expect.stringContaining('at HTMLButtonElement.onclick') + }) + ); + }); + + test('when an Error is thrown then the plugin records the name, message and stack', async () => { + // Init + document.body.innerHTML = + ''; + const plugin: JsErrorPlugin = new JsErrorPlugin(); + + // Run + plugin.load(context); + // @ts-ignore + document.getElementById('createJSError').click(); + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(1); + // @ts-ignore + expect(record.mock.calls[0][0]).toEqual(JS_ERROR_EVENT_TYPE); + // @ts-ignore + expect(record.mock.calls[0][1]).toMatchObject( + expect.objectContaining({ + version: '1.0.0', + type: 'Error', + message: 'Something went wrong!', + lineno: expect.toBePositive(), + colno: expect.toBePositive(), + filename: + 'https://us-east-1.console.aws.amazon.com/console/home?region=us-east-1#feedback', + stack: expect.stringContaining('at HTMLButtonElement.onclick') + }) + ); + }); + + test('when stackTraceLength is zero then the plugin does not record the stack trace', async () => { + // Init + document.body.innerHTML = + ''; + const plugin: JsErrorPlugin = new JsErrorPlugin({ + stackTraceLength: 0 + }); + + // Run + plugin.load(context); + // @ts-ignore + document.getElementById('createJSError').click(); + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(1); + // @ts-ignore + expect(record.mock.calls[0][0]).toEqual(JS_ERROR_EVENT_TYPE); + // @ts-ignore + expect(record.mock.calls[0][1].stack).toEqual(undefined); + }); + + test('when an object without a name, message and stack is thrown then type, message and stack default values', async () => { + // Init + document.body.innerHTML = + ''; + const plugin: JsErrorPlugin = new JsErrorPlugin({ + stackTraceLength: 150 + }); + + // Run + plugin.load(context); + // @ts-ignore + document.getElementById('createJSError').click(); + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(1); + // @ts-ignore + expect(record.mock.calls[0][0]).toEqual(JS_ERROR_EVENT_TYPE); + // @ts-ignore + expect(record.mock.calls[0][1]).toMatchObject({ + version: '1.0.0', + type: 'error', + message: expect.stringMatching( + /(undefined|uncaught exception: {})/ + ), + lineno: 0, + colno: 0, + filename: + 'https://us-east-1.console.aws.amazon.com/console/home?region=us-east-1#feedback' + }); + }); + + test('when a string is thrown then the plugin records the name and message', async () => { + // Init + document.body.innerHTML = + ''; + const plugin: JsErrorPlugin = new JsErrorPlugin(); + + // Run + plugin.load(context); + // @ts-ignore + document.getElementById('createJSError').click(); + plugin.disable(); + + // Assert + // @ts-ignore + expect(record.mock.calls[0][0]).toEqual(JS_ERROR_EVENT_TYPE); + // @ts-ignore + expect(record.mock.calls[0][1]).toMatchObject({ + version: '1.0.0', + type: 'mystringerror', + message: 'mystringerror', + lineno: 0, + colno: 0, + filename: + 'https://us-east-1.console.aws.amazon.com/console/home?region=us-east-1#feedback' + }); + }); + + test('when number is thrown then the plugin records the error as a string', async () => { + // Init + document.body.innerHTML = + ''; + const plugin: JsErrorPlugin = new JsErrorPlugin(); + + // Run + plugin.load(context); + // @ts-ignore + document.getElementById('createJSError').click(); + plugin.disable(); + + // Assert + // @ts-ignore + expect(record.mock.calls[0][0]).toEqual(JS_ERROR_EVENT_TYPE); + // @ts-ignore + expect(record.mock.calls[0][1]).toMatchObject({ + version: '1.0.0', + type: '5', + message: '5', + lineno: 0, + colno: 0, + filename: + 'https://us-east-1.console.aws.amazon.com/console/home?region=us-east-1#feedback' + }); + }); + + test('when boolean is thrown then the plugin records the error as a string', async () => { + // Init + document.body.innerHTML = + ''; + const plugin: JsErrorPlugin = new JsErrorPlugin(); + + // Run + plugin.load(context); + // @ts-ignore + document.getElementById('createJSError').click(); + plugin.disable(); + + // Assert + // @ts-ignore + expect(record.mock.calls[0][0]).toEqual(JS_ERROR_EVENT_TYPE); + // @ts-ignore + expect(record.mock.calls[0][1]).toMatchObject({ + version: '1.0.0', + type: 'false', + message: 'false', + lineno: 0, + colno: 0, + filename: + 'https://us-east-1.console.aws.amazon.com/console/home?region=us-east-1#feedback' + }); + }); + + test('when plugin disabled then plugin does not record events', async () => { + // Init + document.body.innerHTML = + ''; + const plugin: JsErrorPlugin = new JsErrorPlugin(); + + // Run + plugin.load(context); + plugin.disable(); + + // So that the error doesn't cause the test to fail. + window.addEventListener('error', () => {}); + + // @ts-ignore + document.getElementById('createJSError').click(); + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(0); + }); + + test('when enabled then plugin records events', async () => { + // Init + document.body.innerHTML = + ''; + const plugin: JsErrorPlugin = new JsErrorPlugin(); + + // Run + plugin.load(context); + plugin.disable(); + plugin.enable(); + // @ts-ignore + document.getElementById('createJSError').click(); + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(1); + }); + + test('when the application records a caught primitive then the plugin records the error', async () => { + // Init + const plugin: JsErrorPlugin = new JsErrorPlugin(); + + // Run + plugin.load(context); + plugin.record('MyPrimitiveError'); + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(1); + // @ts-ignore + expect(record.mock.calls[0][0]).toEqual(JS_ERROR_EVENT_TYPE); + // @ts-ignore + expect(record.mock.calls[0][1]).toMatchObject( + expect.objectContaining({ + version: '1.0.0', + type: 'MyPrimitiveError', + message: 'MyPrimitiveError' + }) + ); + }); + + test('when the application records a caught Error object then the plugin records the error', async () => { + // Init + const plugin: JsErrorPlugin = new JsErrorPlugin(); + + // Run + plugin.load(context); + plugin.record(new Error('Error message')); + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(1); + // @ts-ignore + expect(record.mock.calls[0][0]).toEqual(JS_ERROR_EVENT_TYPE); + // @ts-ignore + expect(record.mock.calls[0][1]).toMatchObject( + expect.objectContaining({ + version: '1.0.0', + type: 'Error', + message: 'Error message' + }) + ); + }); + + test('when the application records a caught ErrorEvent object then the plugin records the error', async () => { + // Init + const plugin: JsErrorPlugin = new JsErrorPlugin(); + + const errorEvent = new ErrorEvent('error', { + colno: 1, + error: new Error('Something went wrong!'), + filename: 'main.js', + lineno: 2, + message: 'This should be overwritten by the error message.' + }); + + // Run + plugin.load(context); + plugin.record(errorEvent); + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(1); + // @ts-ignore + expect(record.mock.calls[0][0]).toEqual(JS_ERROR_EVENT_TYPE); + // @ts-ignore + expect(record.mock.calls[0][1]).toMatchObject( + expect.objectContaining({ + version: '1.0.0', + type: 'Error', + message: 'Something went wrong!', + filename: 'main.js', + colno: 1, + lineno: 2 + }) + ); + }); + + test('when the application records a caught empty object then defaults are used', async () => { + // Init + const plugin: JsErrorPlugin = new JsErrorPlugin(); + + // Run + plugin.load(context); + plugin.record({}); + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(1); + // @ts-ignore + expect(record.mock.calls[0][0]).toEqual(JS_ERROR_EVENT_TYPE); + // @ts-ignore + expect(record.mock.calls[0][1]).toMatchObject( + expect.objectContaining({ + version: '1.0.0', + type: 'error', + message: 'undefined' + }) + ); + }); + + test('when the application records a caught Error object then the fileName, lineNumber and columnNumber are used', async () => { + // Init + const plugin: JsErrorPlugin = new JsErrorPlugin(); + + // Run + plugin.load(context); + plugin.record({ + name: 'Error', + message: 'Something went wrong!', + fileName: 'main.js', + lineNumber: 1, + columnNumber: 2 + }); + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(1); + // @ts-ignore + expect(record.mock.calls[0][0]).toEqual(JS_ERROR_EVENT_TYPE); + // @ts-ignore + expect(record.mock.calls[0][1]).toMatchObject( + expect.objectContaining({ + version: '1.0.0', + type: 'Error', + message: 'Something went wrong!', + filename: 'main.js', + lineno: 1, + colno: 2 + }) + ); + }); +}); diff --git a/src/plugins/event-plugins/__tests__/NavigationPlugin.test.ts b/src/plugins/event-plugins/__tests__/NavigationPlugin.test.ts new file mode 100644 index 00000000..2b046404 --- /dev/null +++ b/src/plugins/event-plugins/__tests__/NavigationPlugin.test.ts @@ -0,0 +1,106 @@ +import { + navigationEvent, + performanceEvent, + mockPerformanceObserver, + mockPerformanceObject, + MockPerformanceTiming +} from '../../../test-utils/mock-data'; +import { NavigationPlugin } from '../NavigationPlugin'; +import { context, record } from '../../../test-utils/test-utils'; +import { PERFORMANCE_NAVIGATION_EVENT_TYPE } from '../../utils/constant'; + +const buildNavigationPlugin = () => { + return new NavigationPlugin(); +}; + +describe('NavigationPlugin tests', () => { + beforeEach(() => { + (window as any).performance = performanceEvent.performance(); + (window as any).PerformanceObserver = + performanceEvent.PerformanceObserver; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('When navigation event is present then event is recorded', async () => { + const plugin: NavigationPlugin = buildNavigationPlugin(); + // Run + plugin.load(context); + window.dispatchEvent(new Event('load')); + plugin.disable(); + + expect(record.mock.calls[0][0]).toEqual( + PERFORMANCE_NAVIGATION_EVENT_TYPE + ); + expect(record.mock.calls[0][1]).toEqual( + expect.objectContaining({ + targetUrl: navigationEvent.name, + duration: navigationEvent.duration, + startTime: navigationEvent.startTime, + navigationType: navigationEvent.type + }) + ); + }); + + test('When navigation timing level 2 API is not present then navigation timing level 1 API is recorded', async () => { + jest.useFakeTimers(); + // @ts-ignore + mockPerformanceObject(); + mockPerformanceObserver(); + + const plugin: NavigationPlugin = buildNavigationPlugin(); + + plugin.load(context); + window.dispatchEvent(new Event('load')); + plugin.disable(); + + jest.runAllTimers(); + + expect(record).toHaveBeenCalledTimes(1); + expect(record.mock.calls[0][0]).toEqual( + PERFORMANCE_NAVIGATION_EVENT_TYPE + ); + + expect(record.mock.calls[0][1]).toEqual( + expect.objectContaining({ + domComplete: + MockPerformanceTiming.domComplete - + MockPerformanceTiming.navigationStart, + responseStart: + MockPerformanceTiming.responseStart - + MockPerformanceTiming.navigationStart, + initiatorType: 'navigation', + redirectStart: MockPerformanceTiming.redirectStart, + navigationTimingLevel: 1 + }) + ); + }); + + test('when enabled then events are recorded', async () => { + // enables plugin by default + const plugin: NavigationPlugin = buildNavigationPlugin(); + + plugin.load(context); + window.dispatchEvent(new Event('load')); + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalled(); + }); + + test('when disabled then no events are recorded', async () => { + // enables plugin by default + const plugin: NavigationPlugin = buildNavigationPlugin(); + + // adds eventListener on load event + plugin.load(context); + plugin.disable(); + window.dispatchEvent(new Event('load')); + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(0); + }); +}); diff --git a/src/plugins/event-plugins/__tests__/PageViewPlugin.test.ts b/src/plugins/event-plugins/__tests__/PageViewPlugin.test.ts new file mode 100644 index 00000000..0ca92330 --- /dev/null +++ b/src/plugins/event-plugins/__tests__/PageViewPlugin.test.ts @@ -0,0 +1,168 @@ +import { PAGE_ID_FORMAT } from '../../../orchestration/Orchestration'; +import { context } from '../../../test-utils/test-utils'; +import { PageViewPlugin } from '../PageViewPlugin'; + +const PAGE_VIEW_ONE_PATH = '/page_view_one?region=us-west-1#lang'; +const PAGE_VIEW_TWO_PATH = '/page_view_two?region=us-west-1#lang'; + +const PAGE_VIEW_ONE_EXPECTED_PAGE_ID = '/page_view_one'; +const PAGE_VIEW_TWO_EXPECTED_PAGE_ID = '/page_view_two'; + +describe('PageViewPlugin tests', () => { + let url; + + beforeAll(() => { + url = window.location.toString(); + }); + + beforeEach(() => { + // @ts-ignore + context.recordPageView.mockClear(); + // @ts-ignore + jsdom.reconfigure({ + url: url + }); + }); + + test('when pushState is called then a page view event is recorded.', async () => { + // Init + const plugin = new PageViewPlugin(); + plugin.load(context); + + // Run + window.history.pushState( + { state: 'one' }, + 'Page One', + PAGE_VIEW_ONE_PATH + ); + window.history.pushState( + { state: 'two' }, + 'Page Two', + PAGE_VIEW_TWO_PATH + ); + + // Assert + // @ts-ignore + expect(context.recordPageView.mock.calls[0][0]).toEqual( + PAGE_VIEW_ONE_EXPECTED_PAGE_ID + ); + // @ts-ignore + expect(context.recordPageView.mock.calls[1][0]).toEqual( + PAGE_VIEW_TWO_EXPECTED_PAGE_ID + ); + + // @ts-ignore + window.removeEventListener('popstate', plugin.popstateListener); + }); + + test('when window.history.replaceState() is called then a page view event is recorded', async () => { + // Init + const plugin = new PageViewPlugin(); + plugin.load(context); + + // Run + window.history.replaceState( + { state: 'one' }, + 'Page One', + PAGE_VIEW_ONE_PATH + ); + + // Assert + // @ts-ignore + expect(context.recordPageView.mock.calls[0][0]).toEqual( + PAGE_VIEW_ONE_EXPECTED_PAGE_ID + ); + + // @ts-ignore + window.removeEventListener('popstate', plugin.popstateListener); + }); + + test('when a popstate event occurs then a page view event is recorded', async () => { + // Init + const plugin = new PageViewPlugin(); + plugin.load(context); + + // Run + window.history.pushState({}, '', PAGE_VIEW_ONE_PATH); + dispatchEvent(new PopStateEvent('popstate')); + + // Assert + // @ts-ignore + expect(context.recordPageView.mock.calls[0][0]).toEqual( + PAGE_VIEW_ONE_EXPECTED_PAGE_ID + ); + + // @ts-ignore + window.removeEventListener('popstate', plugin.popstateListener); + }); + + test('when PATH_AND_HASH is used then a the path and hash is recorded.', async () => { + // Init + const plugin = new PageViewPlugin(); + context.config.pageIdFormat = PAGE_ID_FORMAT.PATH_AND_HASH; + plugin.load(context); + + // Run + window.history.pushState( + { state: 'one' }, + 'Page One', + PAGE_VIEW_ONE_PATH + ); + + // Assert + // @ts-ignore + expect(context.recordPageView.mock.calls[0][0]).toEqual( + '/page_view_one#lang' + ); + + context.config.pageIdFormat = PAGE_ID_FORMAT.PATH; + // @ts-ignore + window.removeEventListener('popstate', plugin.popstateListener); + }); + + test('when HASH is used then a the hash is recorded.', async () => { + // Init + const plugin = new PageViewPlugin(); + context.config.pageIdFormat = PAGE_ID_FORMAT.HASH; + plugin.load(context); + + // Run + window.history.pushState( + { state: 'one' }, + 'Page One', + PAGE_VIEW_ONE_PATH + ); + + // Assert + // @ts-ignore + expect(context.recordPageView.mock.calls[0][0]).toEqual('#lang'); + + context.config.pageIdFormat = PAGE_ID_FORMAT.PATH; + // @ts-ignore + window.removeEventListener('popstate', plugin.popstateListener); + }); + + test('when there is no hash in the URL then only the path is recorded.', async () => { + // Init + const plugin = new PageViewPlugin(); + context.config.pageIdFormat = PAGE_ID_FORMAT.PATH_AND_HASH; + plugin.load(context); + + // Run + window.history.pushState( + { state: 'one' }, + 'Page One', + '/page_view_one' + ); + + // Assert + // @ts-ignore + expect(context.recordPageView.mock.calls[0][0]).toEqual( + PAGE_VIEW_ONE_EXPECTED_PAGE_ID + ); + + context.config.pageIdFormat = PAGE_ID_FORMAT.PATH; + // @ts-ignore + window.removeEventListener('popstate', plugin.popstateListener); + }); +}); diff --git a/src/plugins/event-plugins/__tests__/PaintPlugin.test.ts b/src/plugins/event-plugins/__tests__/PaintPlugin.test.ts new file mode 100644 index 00000000..0b65d012 --- /dev/null +++ b/src/plugins/event-plugins/__tests__/PaintPlugin.test.ts @@ -0,0 +1,86 @@ +import { + firstPaintEvent, + performanceEvent, + mockPaintPerformanceObject, + mockPaintPerformanceObserver +} from '../../../test-utils/mock-data'; +import { PaintPlugin } from '../PaintPlugin'; +import { context, record } from '../../../test-utils/test-utils'; +import { PERFORMANCE_FIRST_PAINT_EVENT_TYPE } from '../../utils/constant'; + +const DATA_PLANE_URL = 'https://dataplane.us-west-2.beta.rum.aws.dev'; + +const buildPaintPlugin = () => { + return new PaintPlugin(DATA_PLANE_URL); +}; + +describe('PaintPlugin tests', () => { + beforeEach(() => { + (window as any).performance = performanceEvent.performance(); + (window as any).PerformanceObserver = + performanceEvent.PerformanceObserver; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('When paint event is present then event is recorded', async () => { + const plugin: PaintPlugin = buildPaintPlugin(); + + // Run + plugin.load(context); + window.dispatchEvent(new Event('load')); + plugin.disable(); + + expect(record.mock.calls[0][0]).toEqual( + PERFORMANCE_FIRST_PAINT_EVENT_TYPE + ); + expect(record.mock.calls[0][1]).toEqual( + expect.objectContaining({ + version: '1.0.0', + duration: firstPaintEvent.duration, + startTime: firstPaintEvent.startTime + }) + ); + }); + + test('When first paint event is not present then event is derived from resource events', async () => { + mockPaintPerformanceObject(); + mockPaintPerformanceObserver(); + + const plugin: PaintPlugin = buildPaintPlugin(); + + plugin.load(context); + window.dispatchEvent(new Event('load')); + plugin.disable(); + + expect(record).toHaveBeenCalledTimes(1); + expect(record.mock.calls[0][0]).toEqual( + PERFORMANCE_FIRST_PAINT_EVENT_TYPE + ); + }); + + test('when enabled then events are recorded', async () => { + const plugin: PaintPlugin = buildPaintPlugin(); + + plugin.load(context); + window.dispatchEvent(new Event('load')); + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalled(); + }); + + test('when disabled then no events are recorded', async () => { + const plugin: PaintPlugin = buildPaintPlugin(); + + plugin.load(context); + plugin.disable(); + window.dispatchEvent(new Event('load')); + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(0); + }); +}); diff --git a/src/plugins/event-plugins/__tests__/ResourcePlugin.test.ts b/src/plugins/event-plugins/__tests__/ResourcePlugin.test.ts new file mode 100644 index 00000000..a24c776f --- /dev/null +++ b/src/plugins/event-plugins/__tests__/ResourcePlugin.test.ts @@ -0,0 +1,186 @@ +import { + scriptResourceEvent, + imageResourceEvent, + cssResourceEvent, + performanceEvent, + mockPerformanceObserver, + mockPerformanceObject, + mockPerformanceObjectWithResources, + resourceEvent +} from '../../../test-utils/mock-data'; +import { defaultRepConfig, ResourcePlugin } from '../ResourcePlugin'; +import { mockRandom } from 'jest-mock-random'; +import { context, record } from '../../../test-utils/test-utils'; +import { PERFORMANCE_RESOURCE_EVENT_TYPE } from '../../utils/constant'; + +const DATA_PLANE_URL = 'https://dataplane.us-west-2.beta.rum.aws.dev'; + +const buildResourcePlugin = () => { + return new ResourcePlugin(DATA_PLANE_URL); +}; + +describe('ResourcePlugin tests', () => { + beforeEach(() => { + (window as any).performance = performanceEvent.performance(); + (window as any).PerformanceObserver = + performanceEvent.PerformanceObserver; + record.mockClear(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('When resource event is present then event is recorded', async () => { + // Setup + mockRandom(0); // Retain order in shuffle + + const plugin: ResourcePlugin = buildResourcePlugin(); + + // Run + plugin.load(context); + window.dispatchEvent(new Event('load')); + plugin.disable(); + + // Assert + expect(record.mock.calls[0][0]).toEqual( + PERFORMANCE_RESOURCE_EVENT_TYPE + ); + expect(record.mock.calls[0][1]).toEqual( + expect.objectContaining({ + targetUrl: resourceEvent.name, + duration: resourceEvent.duration, + startTime: resourceEvent.startTime + }) + ); + }); + + test('when resource is from data plane endpoint then resource event is not recorded', async () => { + // Setup + mockPerformanceObject(); + mockPerformanceObserver(); + + const plugin: ResourcePlugin = buildResourcePlugin(); + + // Run + plugin.load(context); + window.dispatchEvent(new Event('load')); + plugin.disable(); + + // Assert + expect(record).not.toHaveBeenCalled(); + }); + + test('when enabled then events are recorded', async () => { + // Setup + const plugin: ResourcePlugin = buildResourcePlugin(); + + // Run + plugin.load(context); + plugin.disable(); + plugin.enable(); + window.dispatchEvent(new Event('load')); + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalled(); + }); + + test('when disabled then no events are recorded', async () => { + // Setup + const plugin: ResourcePlugin = buildResourcePlugin(); + + // Run + plugin.load(context); + plugin.disable(); + window.dispatchEvent(new Event('load')); + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(0); + }); + + test('when event limit is reached no more events are recorded', async () => { + // Setup + mockPerformanceObjectWithResources(); + mockPerformanceObserver(); + + const plugin: ResourcePlugin = buildResourcePlugin(); + plugin.configure({ ...defaultRepConfig, ...{ eventLimit: 1 } }); + + // Run + plugin.load(context); + window.dispatchEvent(new Event('load')); + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(1); + }); + + test('when resources > eventLimit then recordAll events are prioritized', async () => { + // Setup + mockRandom(0); // Reverse order in shuffle + mockPerformanceObjectWithResources(); + mockPerformanceObserver(); + + // Run + const plugin: ResourcePlugin = buildResourcePlugin(); + plugin.configure({ ...defaultRepConfig, ...{ eventLimit: 1 } }); + + plugin.load(context); + window.dispatchEvent(new Event('load')); + + plugin.disable(); + + // Assert + expect(record.mock.calls[0][0]).toEqual( + PERFORMANCE_RESOURCE_EVENT_TYPE + ); + expect(record.mock.calls[0][1]).toEqual( + expect.objectContaining({ + targetUrl: scriptResourceEvent.name + }) + ); + }); + + test('sampled events are randomized', async () => { + // Setup + mockPerformanceObjectWithResources(); + mockPerformanceObserver(); + + const plugin: ResourcePlugin = buildResourcePlugin(); + plugin.configure({ ...defaultRepConfig, ...{ eventLimit: 3 } }); + + // Run + plugin.load(context); + + mockRandom(0.99); // Retain order in shuffle + window.dispatchEvent(new Event('load')); + mockRandom(0); // Reverse order in shuffle + window.dispatchEvent(new Event('load')); + + plugin.disable(); + + // Assert + expect(record.mock.calls[1][1]).toEqual( + expect.objectContaining({ + targetUrl: cssResourceEvent.name + }) + ); + expect(record.mock.calls[2][1]).toEqual( + expect.objectContaining({ + targetUrl: imageResourceEvent.name + }) + ); + expect(record.mock.calls[4][1]).toEqual( + expect.objectContaining({ + targetUrl: imageResourceEvent.name + }) + ); + expect(record.mock.calls[5][1]).toEqual( + expect.objectContaining({ + targetUrl: cssResourceEvent.name + }) + ); + }); +}); diff --git a/src/plugins/event-plugins/__tests__/WebVitalsPlugin.test.ts b/src/plugins/event-plugins/__tests__/WebVitalsPlugin.test.ts new file mode 100644 index 00000000..6fbb5b06 --- /dev/null +++ b/src/plugins/event-plugins/__tests__/WebVitalsPlugin.test.ts @@ -0,0 +1,113 @@ +import { WebVitalsPlugin } from '../WebVitalsPlugin'; +import { context, record } from '../../../test-utils/test-utils'; +import { + CLS_EVENT_TYPE, + FID_EVENT_TYPE, + LCP_EVENT_TYPE +} from '../../utils/constant'; + +const mockLCPData = { + delta: 239.51, + id: 'v1-1621403597701-7933189041053', + name: 'LCP', + value: 239.51 +}; + +const mockFIDData = { + delta: 1.2799999676644802, + id: 'v1-1621403597702-6132885858466', + name: 'FID', + value: 1.2799999676644802 +}; + +const mockCLSData = { + delta: 0, + id: 'v1-1621403597702-8740659462223', + name: 'CLS', + value: 0.037451866876684094 +}; + +jest.mock('web-vitals', () => { + return { + getLCP: jest + .fn() + .mockImplementation((callback) => + callback(mockLCPData, LCP_EVENT_TYPE) + ), + getFID: jest + .fn() + .mockImplementation((callback) => + callback(mockFIDData, FID_EVENT_TYPE) + ), + getCLS: jest + .fn() + .mockImplementation((callback) => + callback(mockCLSData, CLS_EVENT_TYPE) + ) + }; +}); + +describe('WebVitalsPlugin tests', () => { + beforeEach(() => { + record.mockClear(); + }); + + test('When web vitals are present then events are recorded', async () => { + // Setup + const plugin: WebVitalsPlugin = new WebVitalsPlugin(); + + // Run + plugin.load(context); + window.dispatchEvent(new Event('load')); + + // Assert + expect(record).toHaveBeenCalledTimes(3); + + expect(record.mock.calls[0][0]).toEqual(LCP_EVENT_TYPE); + expect(record.mock.calls[0][1]).toEqual( + expect.objectContaining({ + version: '1.0.0', + value: mockLCPData.value + }) + ); + + expect(record.mock.calls[1][0]).toEqual(FID_EVENT_TYPE); + expect(record.mock.calls[1][1]).toEqual( + expect.objectContaining({ + version: '1.0.0', + value: mockFIDData.value + }) + ); + + expect(record.mock.calls[2][0]).toEqual(CLS_EVENT_TYPE); + expect(record.mock.calls[2][1]).toEqual( + expect.objectContaining({ + version: '1.0.0', + value: mockCLSData.value + }) + ); + }); + + test('Disable and enable does not have effect on the plugin behavior', async () => { + const plugin: WebVitalsPlugin = new WebVitalsPlugin(); + + plugin.load(context); + plugin.disable(); + plugin.enable(); + window.dispatchEvent(new Event('load')); + + // Assert + expect(record).toHaveBeenCalled(); + }); + + test('Disable does not have effect on the plugin behavior', async () => { + const plugin: WebVitalsPlugin = new WebVitalsPlugin(); + + plugin.load(context); + plugin.disable(); + window.dispatchEvent(new Event('load')); + + // Assert + expect(record).toHaveBeenCalled(); + }); +}); diff --git a/src/plugins/event-plugins/__tests__/XhrPlugin.test.ts b/src/plugins/event-plugins/__tests__/XhrPlugin.test.ts new file mode 100644 index 00000000..a43aff64 --- /dev/null +++ b/src/plugins/event-plugins/__tests__/XhrPlugin.test.ts @@ -0,0 +1,722 @@ +import { HttpPluginConfig } from '../../utils/http-utils'; +import { advanceTo } from 'jest-date-mock'; +import { XhrPlugin } from '../XhrPlugin'; +import { + context, + record, + recordPageView +} from '../../../test-utils/test-utils'; +import mock from 'xhr-mock'; +import { GetSession, PluginContext } from '../../Plugin'; +import { defaultConfig } from '../../../orchestration/Orchestration'; +import { XRAY_TRACE_EVENT_TYPE, HTTP_EVENT_TYPE } from '../../utils/constant'; + +// Mock getRandomValues -- since it does nothing, the 'random' number will be 0. +jest.mock('../../../utils/random'); + +describe('JsErrorPlugin tests', () => { + beforeEach(() => { + advanceTo(0); + mock.setup(); + record.mockClear(); + }); + + test('when XHR is called then the plugin records the http request/response', async () => { + // Init + const config: HttpPluginConfig = { + urlsToInclude: [/response\.json/], + recordAllRequests: true + }; + + mock.get(/.*/, { + body: JSON.stringify({ message: 'Hello World!' }) + }); + + const plugin: XhrPlugin = new XhrPlugin(config); + plugin.load(context); + + // Run + const xhr = new XMLHttpRequest(); + xhr.open('GET', './response.json', true); + xhr.send(); + + // Yield to the event queue so the event listeners can run + await new Promise((resolve) => setTimeout(resolve, 0)); + + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(1); + // @ts-ignore + expect(record.mock.calls[0][0]).toEqual(HTTP_EVENT_TYPE); + // @ts-ignore + expect(record.mock.calls[0][1]).toMatchObject({ + request: { + method: 'GET', + url: './response.json' + }, + response: { + status: 200, + statusText: 'OK' + } + }); + }); + + test('when XHR is called then the plugin records a trace', async () => { + // Init + const config: HttpPluginConfig = { + logicalServiceName: 'sample.rum.aws.amazon.com', + urlsToInclude: [/response\.json/], + trace: true + }; + + mock.get(/.*/, { + body: JSON.stringify({ message: 'Hello World!' }) + }); + + const plugin: XhrPlugin = new XhrPlugin(config); + plugin.load(context); + + // Run + const xhr = new XMLHttpRequest(); + xhr.open('GET', './response.json', true); + xhr.send(); + + // Yield to the event queue so the event listeners can run + await new Promise((resolve) => setTimeout(resolve, 0)); + + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(1); + // @ts-ignore + expect(record.mock.calls[0][0]).toEqual(XRAY_TRACE_EVENT_TYPE); + // @ts-ignore + expect(record.mock.calls[0][1]).toMatchObject({ + in_progress: false, + name: 'sample.rum.aws.amazon.com', + id: '0000000000000000', + start_time: 0, + trace_id: '1-0-000000000000000000000000', + end_time: 0, + http: { + request: { + method: 'GET', + traced: true, + url: './response.json' + }, + response: { status: 200 } + } + }); + }); + + test('when plugin is disabled then the plugin does not record any events', async () => { + // Init + const config: HttpPluginConfig = { + urlsToInclude: [/response\.json/], + trace: true, + recordAllRequests: true + }; + + mock.get(/.*/, { + body: JSON.stringify({ message: 'Hello World!' }) + }); + + const plugin: XhrPlugin = new XhrPlugin(config); + plugin.load(context); + plugin.disable(); + + // Run + const xhr = new XMLHttpRequest(); + xhr.open('GET', './response.json', true); + xhr.send(); + + // Yield to the event queue so the event listeners can run + await new Promise((resolve) => setTimeout(resolve, 0)); + + // Assert + expect(record).not.toHaveBeenCalled(); + }); + + test('when plugin is re-enabled then the plugin records a trace', async () => { + // Init + const config: HttpPluginConfig = { + urlsToInclude: [/response\.json/], + trace: true + }; + + mock.get(/.*/, { + body: JSON.stringify({ message: 'Hello World!' }) + }); + + const plugin: XhrPlugin = new XhrPlugin(config); + plugin.load(context); + plugin.disable(); + plugin.enable(); + + // Run + const xhr = new XMLHttpRequest(); + xhr.open('GET', './response.json', true); + xhr.send(); + + // Yield to the event queue so the event listeners can run + await new Promise((resolve) => setTimeout(resolve, 0)); + + plugin.disable(); + + // Assert + // @ts-ignore + expect(record.mock.calls[0][0]).toEqual(XRAY_TRACE_EVENT_TYPE); + }); + + test('when XHR returns an error code then the plugin adds the error to the trace', async () => { + // Init + const config: HttpPluginConfig = { + ...defaultConfig, + ...{ + logicalServiceName: 'sample.rum.aws.amazon.com', + urlsToInclude: [/response\.json/], + trace: true + } + }; + + mock.get(/.*/, () => Promise.reject(new Error())); + + const plugin: XhrPlugin = new XhrPlugin(config); + plugin.load(context); + + // Run + const xhr = new XMLHttpRequest(); + xhr.open('GET', './response.json', true); + xhr.send(); + + // Yield to the event queue so the event listeners can run + await new Promise((resolve) => setTimeout(resolve, 0)); + + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(2); + // @ts-ignore + expect(record.mock.calls[0][0]).toEqual(XRAY_TRACE_EVENT_TYPE); + // @ts-ignore + expect(record.mock.calls[0][1]).toMatchObject({ + in_progress: false, + name: 'sample.rum.aws.amazon.com', + id: '0000000000000000', + start_time: 0, + trace_id: '1-0-000000000000000000000000', + end_time: 0, + http: { + request: { + method: 'GET', + traced: true, + url: './response.json' + } + }, + cause: { + exceptions: [ + { + type: 'XMLHttpRequest error' + } + ] + } + }); + }); + + test('when XHR returns an error code then the plugin adds the error to the http event', async () => { + // Init + const config: HttpPluginConfig = { + logicalServiceName: 'sample.rum.aws.amazon.com', + urlsToInclude: [/response\.json/], + trace: false + }; + + mock.get(/.*/, () => Promise.reject(new Error('Network failure'))); + + const plugin: XhrPlugin = new XhrPlugin(config); + plugin.load(context); + + // Run + const xhr = new XMLHttpRequest(); + xhr.open('GET', './response.json', true); + xhr.send(); + + // Yield to the event queue so the event listeners can run + await new Promise((resolve) => setTimeout(resolve, 0)); + + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(1); + // @ts-ignore + expect(record.mock.calls[0][0]).toEqual(HTTP_EVENT_TYPE); + // @ts-ignore + expect(record.mock.calls[0][1]).toMatchObject({ + request: { + method: 'GET', + url: './response.json' + }, + error: { + type: 'XMLHttpRequest error', + message: '0' + } + }); + }); + + test('when XHR times out then the plugin adds the error to the trace', async () => { + // Init + const config: HttpPluginConfig = { + logicalServiceName: 'sample.rum.aws.amazon.com', + urlsToInclude: [/response\.json/], + trace: true + }; + + mock.get(/.*/, () => new Promise(() => {})); + + const plugin: XhrPlugin = new XhrPlugin(config); + plugin.load(context); + + // Run + const xhr = new XMLHttpRequest(); + xhr.open('GET', './response.json', true); + xhr.timeout = 1; + xhr.send(); + + // Yield to the event queue so the event listeners can run + await new Promise((resolve) => setTimeout(resolve, 0)); + + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(2); + // @ts-ignore + expect(record.mock.calls[0][0]).toEqual(XRAY_TRACE_EVENT_TYPE); + // @ts-ignore + expect(record.mock.calls[0][1]).toMatchObject({ + in_progress: false, + name: 'sample.rum.aws.amazon.com', + id: '0000000000000000', + start_time: 0, + trace_id: '1-0-000000000000000000000000', + end_time: 0, + cause: { + exceptions: [ + { + type: 'XMLHttpRequest timeout' + } + ] + } + }); + }); + + test('when XHR times out then the plugin adds the error to the http event', async () => { + // Init + const config: HttpPluginConfig = { + logicalServiceName: 'sample.rum.aws.amazon.com', + urlsToInclude: [/response\.json/], + trace: false + }; + + mock.get(/.*/, () => new Promise(() => {})); + + const plugin: XhrPlugin = new XhrPlugin(config); + plugin.load(context); + + // Run + const xhr = new XMLHttpRequest(); + xhr.open('GET', './response.json', true); + xhr.timeout = 1; + xhr.send(); + + // Yield to the event queue so the event listeners can run + await new Promise((resolve) => setTimeout(resolve, 0)); + + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(1); + // @ts-ignore + expect(record.mock.calls[0][0]).toEqual(HTTP_EVENT_TYPE); + // @ts-ignore + expect(record.mock.calls[0][1]).toMatchObject({ + request: { + method: 'GET', + url: './response.json' + }, + error: { + type: 'XMLHttpRequest timeout' + } + }); + }); + + test('when XHR aborts then the plugin adds the error to the trace', async () => { + // Init + const config: HttpPluginConfig = { + logicalServiceName: 'sample.rum.aws.amazon.com', + urlsToInclude: [/response\.json/], + trace: true + }; + + mock.get(/.*/, { + body: JSON.stringify({ message: 'Hello World!' }) + }); + + const plugin: XhrPlugin = new XhrPlugin(config); + plugin.load(context); + + // Run + const xhr = new XMLHttpRequest(); + xhr.open('GET', './response.json', true); + xhr.send(); + xhr.abort(); + + // Yield to the event queue so the event listeners can run + await new Promise((resolve) => setTimeout(resolve, 0)); + + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(2); + // @ts-ignore + expect(record.mock.calls[0][0]).toEqual(XRAY_TRACE_EVENT_TYPE); + // @ts-ignore + expect(record.mock.calls[0][1]).toMatchObject({ + in_progress: false, + name: 'sample.rum.aws.amazon.com', + id: '0000000000000000', + start_time: 0, + trace_id: '1-0-000000000000000000000000', + end_time: 0, + cause: { + exceptions: [ + { + type: 'XMLHttpRequest abort' + } + ] + } + }); + }); + + test('when XHR aborts then the plugin adds the error to the http event', async () => { + // Init + const config: HttpPluginConfig = { + urlsToInclude: [/response\.json/], + trace: false + }; + + mock.get(/.*/, { + body: JSON.stringify({ message: 'Hello World!' }) + }); + + const plugin: XhrPlugin = new XhrPlugin(config); + plugin.load(context); + + // Run + const xhr = new XMLHttpRequest(); + xhr.open('GET', './response.json', true); + xhr.send(); + xhr.abort(); + + // Yield to the event queue so the event listeners can run + await new Promise((resolve) => setTimeout(resolve, 0)); + + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalledTimes(1); + // @ts-ignore + expect(record.mock.calls[0][0]).toEqual(HTTP_EVENT_TYPE); + // @ts-ignore + expect(record.mock.calls[0][1]).toMatchObject({ + request: { + method: 'GET', + url: './response.json' + }, + error: { + type: 'XMLHttpRequest abort' + } + }); + }); + + test('X-Amzn-Trace-Id header is added to the HTTP request', async () => { + // Init + let header: string; + const config: HttpPluginConfig = { + urlsToInclude: [/response\.json/], + trace: true + }; + + // @ts-ignore + mock.get(/.*/, (req, res) => { + header = req.header('X-Amzn-Trace-Id'); + return res + .status(200) + .body(JSON.stringify({ message: 'Hello World!' })); + }); + + const plugin: XhrPlugin = new XhrPlugin(config); + plugin.load(context); + + // Run + const xhr = new XMLHttpRequest(); + xhr.open('GET', './response.json', true); + xhr.setRequestHeader('Blarb', 'gurggle'); + xhr.send(); + + // Yield to the event queue so the event listeners can run + await new Promise((resolve) => setTimeout(resolve, 0)); + + plugin.disable(); + + // Assert + expect(header).toEqual( + 'Root=1-0-000000000000000000000000;Parent=0000000000000000;Sampled=1' + ); + }); + + test('when trace is disabled then the plugin does not record a trace', async () => { + // Init + const config: HttpPluginConfig = { + urlsToInclude: [/response\.json/], + trace: false + }; + + mock.get(/.*/, { + body: JSON.stringify({ message: 'Hello World!' }) + }); + + const plugin: XhrPlugin = new XhrPlugin(config); + plugin.load(context); + + // Run + const xhr = new XMLHttpRequest(); + xhr.open('GET', './response.json', true); + xhr.send(); + + // Yield to the event queue so the event listeners can run + await new Promise((resolve) => setTimeout(resolve, 0)); + + plugin.disable(); + + // Assert + expect(record).not.toHaveBeenCalled(); + }); + + test('when session is not being recorded then the plugin does not record a trace', async () => { + // Init + const getSession: jest.MockedFunction = jest.fn(() => ({ + sessionId: 'abc123', + record: false, + eventCount: 0 + })); + const context: PluginContext = { + applicationName: 'a', + applicationId: 'b', + applicationVersion: '1.0', + config: defaultConfig, + record, + recordPageView, + getSession + }; + const config: HttpPluginConfig = { + logicalServiceName: 'sample.rum.aws.amazon.com', + urlsToInclude: [/response\.json/] + }; + + mock.get(/.*/, { + body: JSON.stringify({ message: 'Hello World!' }) + }); + + const plugin: XhrPlugin = new XhrPlugin(config); + plugin.load(context); + + // Run + const xhr = new XMLHttpRequest(); + xhr.open('GET', './response.json', true); + xhr.send(); + + // Yield to the event queue so the event listeners can run + await new Promise((resolve) => setTimeout(resolve, 0)); + + plugin.disable(); + + // Assert + expect(record).not.toHaveBeenCalled(); + }); + + test('when recordAllRequests is false then the plugin does record a request with status OK', async () => { + // Init + const config: HttpPluginConfig = { + urlsToInclude: [/response\.json/], + recordAllRequests: true + }; + + mock.get(/.*/, { + body: JSON.stringify({ message: 'Hello World!' }) + }); + + const plugin: XhrPlugin = new XhrPlugin(config); + plugin.load(context); + + // Run + const xhr = new XMLHttpRequest(); + xhr.open('GET', './response.json', true); + xhr.send(); + + // Yield to the event queue so the event listeners can run + await new Promise((resolve) => setTimeout(resolve, 0)); + + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalled(); + }); + + test('when recordAllRequests is false then the plugin does not record a request with status OK', async () => { + // Init + const config: HttpPluginConfig = { + urlsToInclude: [/response\.json/], + recordAllRequests: false + }; + + mock.get(/.*/, { + body: JSON.stringify({ message: 'Hello World!' }) + }); + + const plugin: XhrPlugin = new XhrPlugin(config); + plugin.load(context); + + // Run + const xhr = new XMLHttpRequest(); + xhr.open('GET', './response.json', true); + xhr.send(); + + // Yield to the event queue so the event listeners can run + await new Promise((resolve) => setTimeout(resolve, 0)); + + plugin.disable(); + + // Assert + expect(record).not.toHaveBeenCalled(); + }); + + test('when recordAllRequests is false then the plugin records a request with status 500', async () => { + // Init + const config: HttpPluginConfig = { + urlsToInclude: [/response\.json/], + recordAllRequests: false + }; + + mock.get(/.*/, { + status: 500, + body: 'InternalError' + }); + + const plugin: XhrPlugin = new XhrPlugin(config); + plugin.load(context); + + // Run + const xhr = new XMLHttpRequest(); + xhr.open('GET', './response.json', true); + xhr.send(); + + // Yield to the event queue so the event listeners can run + await new Promise((resolve) => setTimeout(resolve, 0)); + + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalled(); + }); + + test('when a url is excluded then the plugin does not record a request to that url', async () => { + // Init + const config: HttpPluginConfig = { + urlsToInclude: [/response\.json/], + urlsToExclude: [/response\.json/] + }; + + mock.get(/.*/, { + body: JSON.stringify({ message: 'Hello World!' }) + }); + + const plugin: XhrPlugin = new XhrPlugin(config); + plugin.load(context); + + // Run + const xhr = new XMLHttpRequest(); + xhr.open('GET', './response.json', true); + xhr.send(); + + // Yield to the event queue so the event listeners can run + await new Promise((resolve) => setTimeout(resolve, 0)); + + plugin.disable(); + + // Assert + expect(record).not.toHaveBeenCalled(); + }); + + test('all urls are included by default', async () => { + // Init + const config: HttpPluginConfig = { + recordAllRequests: true + }; + + mock.get(/.*/, { + body: JSON.stringify({ message: 'Hello World!' }) + }); + + const plugin: XhrPlugin = new XhrPlugin(config); + plugin.load(context); + + // Run + const xhr = new XMLHttpRequest(); + xhr.open('GET', './response.json', true); + xhr.send(); + + // Yield to the event queue so the event listeners can run + await new Promise((resolve) => setTimeout(resolve, 0)); + + plugin.disable(); + + // Assert + expect(record).toHaveBeenCalled(); + }); + + test('when a request is made to cognito or sts using default exclude list then the requests are not recorded', async () => { + // Init + const config: HttpPluginConfig = { + recordAllRequests: true + }; + + mock.get(/.*/, { + body: JSON.stringify({}) + }); + + const plugin: XhrPlugin = new XhrPlugin(config); + plugin.load(context); + + // Run + const xhr_cognito = new XMLHttpRequest(); + xhr_cognito.open( + 'GET', + 'https://cognito-identity.us-west-2.amazonaws.com', + true + ); + xhr_cognito.send(); + + const xhr_sts = new XMLHttpRequest(); + xhr_sts.open('GET', 'https://sts.us-west-2.amazonaws.com', true); + xhr_sts.send(); + + // Yield to the event queue so the event listeners can run + await new Promise((resolve) => setTimeout(resolve, 0)); + + plugin.disable(); + + // Assert + expect(record).not.toHaveBeenCalled(); + }); +}); diff --git a/src/plugins/utils/constant.ts b/src/plugins/utils/constant.ts new file mode 100644 index 00000000..49a063c4 --- /dev/null +++ b/src/plugins/utils/constant.ts @@ -0,0 +1,26 @@ +export const UNKNOWN = 'unknown'; + +// Http request event schemas +export const HTTP_EVENT_TYPE = 'com.amazon.rum.http_event'; +export const XRAY_TRACE_EVENT_TYPE = 'com.amazon.rum.xray_trace_event'; + +// Web vitals event schemas +export const LCP_EVENT_TYPE = 'com.amazon.rum.largest_contentful_paint_event'; +export const FID_EVENT_TYPE = 'com.amazon.rum.first_input_delay_event'; +export const CLS_EVENT_TYPE = 'com.amazon.rum.cumulative_layout_shift_event'; + +// Page load event schemas +export const PERFORMANCE_NAVIGATION_EVENT_TYPE = + 'com.amazon.rum.performance_navigation_event'; +export const PERFORMANCE_RESOURCE_EVENT_TYPE = + 'com.amazon.rum.performance_resource_event'; +export const PERFORMANCE_FIRST_PAINT_EVENT_TYPE = + 'com.amazon.rum.performance_first_paint_event'; +export const PERFORMANCE_FIRST_CONTENTFUL_PAINT_EVENT_TYPE = + 'com.amazon.rum.performance_first_contentful_paint_event'; + +// DOM event schemas +export const DOM_EVENT_TYPE = 'com.amazon.rum.dom_event'; + +// JS error event schemas +export const JS_ERROR_EVENT_TYPE = 'com.amazon.rum.js_error_event'; diff --git a/src/plugins/utils/http-utils.ts b/src/plugins/utils/http-utils.ts new file mode 100644 index 00000000..ddac437b --- /dev/null +++ b/src/plugins/utils/http-utils.ts @@ -0,0 +1,172 @@ +import { + Http, + Subsegment, + XRayTraceEvent +} from '../../events/xray-trace-event'; +import { getRandomValues } from '../../utils/random'; + +// All one-byte hex strings from 0x00 to 0xff. +export const byteToHex = []; +for (let i = 0; i < 256; i++) { + byteToHex[i] = (i + 0x100).toString(16).substr(1); +} + +export const X_AMZN_TRACE_ID = 'X-Amzn-Trace-Id'; + +export type HttpPluginConfig = { + logicalServiceName?: string; + urlsToInclude?: RegExp[]; + urlsToExclude?: RegExp[]; + trace?: boolean; + stackTraceLength?: number; + recordAllRequests?: boolean; +}; + +export type HttpPluginConfigWithDefaults = { + logicalServiceName: string; + urlsToInclude: RegExp[]; + urlsToExclude: RegExp[]; + trace: boolean; + stackTraceLength: number; + recordAllRequests: boolean; +}; + +export const defaultConfig: HttpPluginConfigWithDefaults = { + logicalServiceName: 'rum.aws.amazon.com', + urlsToInclude: [/.*/], + urlsToExclude: [ + // Cognito endpoints https://docs.aws.amazon.com/general/latest/gr/cognito_identity.html + /cognito\-identity\.([^\.]*\.)?amazonaws\.com/, + // STS endpoints https://docs.aws.amazon.com/general/latest/gr/sts.html + /sts\.([^\.]*\.)?amazonaws\.com/ + ], + trace: false, + stackTraceLength: 200, + recordAllRequests: false +}; + +export const isUrlAllowed = ( + url: string, + config: HttpPluginConfigWithDefaults +) => { + const include = config.urlsToInclude.some((urlPattern) => + urlPattern.test(url) + ); + const exclude = config.urlsToExclude.some((urlPattern) => + urlPattern.test(url) + ); + return include && !exclude; +}; + +/** + * Returns the current time, in floating point seconds in epoch time, accurate to milliseconds. + */ +export const epochTime = () => { + return Date.now() / 1000; +}; + +export const createXRayTraceEventHttp = ( + input: RequestInfo, + init: RequestInit, + traced: boolean +): Http => { + const http: Http = { request: {} }; + http.request.url = input.toString(); + http.request.method = init.method ? init.method : 'GET'; + http.request.traced = traced; + return http; +}; + +export const createXRayTraceEvent = ( + name: string, + startTime: number, + http?: Http +): XRayTraceEvent => { + const traceEvent: XRayTraceEvent = { + version: '1.0.0', + name, + origin: 'AWS::RUM::Application', + id: generateSegmentId(), + start_time: startTime, + trace_id: generateTraceId(), + end_time: undefined, + subsegments: [], + in_progress: false + }; + if (http) { + traceEvent.http = http; + } + return traceEvent; +}; + +export const createXRaySubsegment = (name: string, startTime): Subsegment => { + return { + id: generateSegmentId(), + name, + start_time: startTime, + end_time: undefined, + in_progress: false + }; +}; + +export const addAmznTraceIdHeader = ( + init: RequestInit, + traceId: string, + segmentId: string +) => { + if (!init.headers) { + init.headers = []; + } + init.headers[X_AMZN_TRACE_ID] = getAmznTraceIdHeaderValue( + traceId, + segmentId + ); +}; + +export const getAmznTraceIdHeaderValue = ( + traceId: string, + segmentId: string +) => { + return 'Root=' + traceId + ';Parent=' + segmentId + ';Sampled=1'; +}; + +/** + * Generate a globally unique trace ID. + * + * See https://docs.aws.amazon.com/xray/latest/devguide/xray-api-sendingdata.html + * @returns a trace id with the form '1-[unix epoch time in 8 hex digits]-[random in 24 hex digits]' + */ +const generateTraceId = (): string => { + return `1-${hexTime()}-${guid()}`; +}; + +/** + * Generate a segment ID that is unique within a trace. + * + * See https://docs.aws.amazon.com/xray/latest/devguide/xray-api-sendingdata.html + * @returns a segment id, which is 16 random hex digits + */ +const generateSegmentId = (): string => { + const randomBytes = new Uint8Array(8); + getRandomValues(randomBytes); + return uint8ArrayToHexString(randomBytes); +}; + +const hexTime = (): string => { + return Math.floor(Date.now() / 1000).toString(16); +}; + +const guid = (): string => { + const randomBytes = new Uint8Array(12); + getRandomValues(randomBytes); + return uint8ArrayToHexString(randomBytes); +}; + +const uint8ArrayToHexString = (bytes: Uint8Array): string => { + let hexString = ''; + // tslint:disable-next-line:prefer-for-of + for (let i = 0; i < bytes.length; i++) { + hexString += byteToHex[bytes[i]]; + } + return hexString; +}; diff --git a/src/plugins/utils/js-error-utils.ts b/src/plugins/utils/js-error-utils.ts new file mode 100644 index 00000000..c14e858f --- /dev/null +++ b/src/plugins/utils/js-error-utils.ts @@ -0,0 +1,97 @@ +import { JSErrorEvent } from '../../events/js-error-event'; + +/** + * Global error object. + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error + */ +interface Error { + message?: string; + name?: string; + description?: string; // non-standard Microsoft property + number?: number; // non-standard Microsoft property + fileName?: string; // non-standard Mozilla property + lineNumber?: number; // non-standard Mozilla property + columnNumber?: number; // non-standard Mozilla property + stack?: string; // non-standard Mozilla and Chrome property +} + +const isObject = (error: any): boolean => { + const type = typeof error; + return (type === 'object' || type === 'function') && !!error; +}; + +const buildBaseJsErrorEvent = (errorEvent: ErrorEvent): JSErrorEvent => { + const rumEvent: JSErrorEvent = { + version: '1.0.0', + type: 'undefined', + message: 'undefined' + }; + if (errorEvent.type !== undefined) { + rumEvent.type = errorEvent.type; + } + if (errorEvent.message !== undefined) { + rumEvent.message = errorEvent.message; + } + if (errorEvent.filename !== undefined) { + rumEvent.filename = errorEvent.filename; + } + if (errorEvent.lineno !== undefined) { + rumEvent.lineno = errorEvent.lineno; + } + if (errorEvent.colno !== undefined) { + rumEvent.colno = errorEvent.colno; + } + return rumEvent; +}; + +const appendErrorPrimitiveDetails = ( + rumEvent: JSErrorEvent, + error: any +): void => { + rumEvent.type = error.toString(); + rumEvent.message = error.toString(); +}; + +const appendErrorObjectDetails = ( + rumEvent: JSErrorEvent, + error: Error, + stackTraceLength: number +): void => { + // error may extend Error here, but it is not guaranteed (i.e., it could + // be any object) + if (error.name) { + rumEvent.type = error.name; + } + if (error.message) { + rumEvent.message = error.message; + } + if (error.fileName) { + rumEvent.filename = error.fileName; + } + if (error.lineNumber) { + rumEvent.lineno = error.lineNumber; + } + if (error.columnNumber) { + rumEvent.colno = error.columnNumber; + } + if (stackTraceLength && error.stack) { + rumEvent.stack = + error.stack.length > stackTraceLength + ? error.stack.substring(0, stackTraceLength) + '...' + : error.stack; + } +}; + +export const errorEventToJsErrorEvent = ( + errorEvent: ErrorEvent, + stackTraceLength: number +): JSErrorEvent => { + const rumEvent: JSErrorEvent = buildBaseJsErrorEvent(errorEvent); + const error = errorEvent.error; + if (isObject(error)) { + appendErrorObjectDetails(rumEvent, error, stackTraceLength); + } else if (error !== undefined && error !== null) { + appendErrorPrimitiveDetails(rumEvent, error); + } + return rumEvent; +}; diff --git a/src/sessions/PageManager.ts b/src/sessions/PageManager.ts new file mode 100644 index 00000000..9de5ea48 --- /dev/null +++ b/src/sessions/PageManager.ts @@ -0,0 +1,156 @@ +import { Config, PAGE_ID_FORMAT } from '../orchestration/Orchestration'; +import { RecordEvent } from '../plugins/Plugin'; +import { PageViewEvent } from '../events/page-view-event'; + +export const PAGE_VIEW_TYPE = 'com.amazon.rum.page_view_event'; +export const PAGE_COOKIE_NAME = 'rum_page_id'; + +export type Page = { + pageId: string; + interaction: number; + parentPageId?: string; + start: number; +}; + +export type Attributes = { + title: string; + url: string; + pageUrl: string; + pageId: string; + parentPageId?: string; + interaction?: number; +}; + +/** + * The page manager keeps the state of the current page and interaction level. + * + * A page is a unique view (user interface) of the application. For 'multi page' applications (i.e., 'classic' web + * applications that have multiple html files), the page changes when the user nagivates to a new web page. For + * 'single page' applications (i.e., 'ajax' web applications that have a single html file), the page changes when (1) + * the popstate event emitted, or (2) the application indicates a new page has loaded using the RUM agent API. + * + * The interaction level is the order of a page in the sequence of pages sorted by the time they were viewed. + */ +export class PageManager { + private config: Config; + private record: RecordEvent; + private page: Page | undefined; + private attributes: Attributes; + + constructor(config: Config, record: RecordEvent) { + this.config = config; + this.record = record; + this.page = undefined; + } + + public getPage(): Page { + return this.page; + } + + public getAttributes(): object { + return this.attributes; + } + + public startSession(): PageViewEvent { + if (!this.page) { + this.page = { + pageId: this.createIdForCurrentPage(), + interaction: 0, + start: Date.now() + }; + } + this.collectAttributes(); + return this.createPageViewEvent(); + } + + public resumeSession(pageId: string, interaction: number) { + this.page = { + pageId: this.createIdForCurrentPage(), + interaction: interaction + 1, + parentPageId: pageId, + start: Date.now() + }; + this.collectAttributes(); + this.recordPageViewEvent(); + } + + public recordPageView(pageId: string) { + if (this.page.pageId === pageId) { + // The view has not changed. + return; + } + this.page = { + pageId, + parentPageId: this.page.pageId, + interaction: this.page.interaction + 1, + start: Date.now() + }; + this.collectAttributes(); + this.recordPageViewEvent(); + } + + private collectAttributes() { + this.attributes = { + title: document.title, + url: document.location.toString(), + pageUrl: document.location.toString(), + pageId: this.page.pageId + }; + + if (this.page.interaction !== undefined) { + this.attributes.interaction = this.page.interaction; + } + + if (this.page.parentPageId !== undefined) { + this.attributes.parentPageId = this.page.parentPageId; + } + } + + private createPageViewEvent() { + const pageViewEvent: PageViewEvent = { + version: '1.0.0', + pageId: this.page.pageId + }; + + if (this.page.interaction !== undefined) { + pageViewEvent.interaction = this.page.interaction; + pageViewEvent.pageInteractionId = + this.page.pageId + '-' + this.page.interaction; + } + + if ( + this.page.parentPageId !== undefined && + this.page.interaction !== undefined + ) { + pageViewEvent.parentPageInteractionId = + this.page.parentPageId + '-' + (this.page.interaction - 1); + } + + return pageViewEvent; + } + + private recordPageViewEvent() { + this.record(PAGE_VIEW_TYPE, this.createPageViewEvent()); + } + + private createIdForCurrentPage(): string { + const path = document.location.pathname; + const hash = document.location.hash; + switch (this.config.pageIdFormat) { + case PAGE_ID_FORMAT.PATH_AND_HASH: + if (path && hash) { + return path + hash; + } else if (path) { + return path; + } else if (hash) { + return hash; + } + return ''; + case PAGE_ID_FORMAT.HASH: + return hash ? hash : ''; + case PAGE_ID_FORMAT.PATH: + default: + return path ? path : ''; + } + } +} diff --git a/src/sessions/SessionManager.ts b/src/sessions/SessionManager.ts new file mode 100644 index 00000000..2a001a76 --- /dev/null +++ b/src/sessions/SessionManager.ts @@ -0,0 +1,249 @@ +import { + storeCookie, + getCookie, + getCookieDomain +} from '../utils/cookies-utils'; + +import { v4 } from 'uuid'; +import { Config } from '../orchestration/Orchestration'; +import { Page, PageManager, PAGE_VIEW_TYPE } from './PageManager'; + +import { UAParser } from 'ua-parser-js'; +import { PageViewEvent } from '../events/page-view-event'; +import { SESSION_COOKIE_NAME, USER_COOKIE_NAME } from '../utils/constants'; + +export const NIL_UUID = '00000000-0000-0000-0000-000000000000'; + +export const UNKNOWN = 'unknown'; +export const DESKTOP_DEVICE_TYPE = 'desktop'; +export const WEB_PLATFORM_TYPE = 'web'; + +export const SESSION_START_EVENT_TYPE = 'com.amazon.rum.session_start_event'; +export const RUM_SESSION_START = 'rum_session_start'; +export const RUM_SESSION_EXPIRE = 'rum_session_expire'; + +export type RecordSessionInitEvent = ( + session: Session, + type: string, + eventData: object +) => void; + +export type Session = { + sessionId: string; + record: boolean; + eventCount: number; + page?: Page; +}; + +export type Attributes = { + browserLanguage: string; + browserName: string; + browserVersion: string; + osName: string; + osVersion: string; + // Possible device types include {console, mobile, tablet, smarttv, wearable, embedded}. If the device + // type is undefined, there was no information indicating the device is anything other than a desktop, + // so we assume the device is a desktop. + deviceType: string; + // This client is used exclusively in web applications. + platformType: string; + // The fully qualified domain name (i.e., host name + domain name) + domain: string; +}; + +/** + * The session handler handles user id and session id. + * + * A session is the {user id, session id} tuple which groups events that occur on a single browser over a continuous + * period of time. A session begins when no session exists or the last session has expired. If user id does not exist, + * session handler will assign a new one and store it in cookie. If session id does not exist or has expired, session + * handler will assign a new one and store it in cookie. Session handler detects user interactions and updates session + * id expiration time. + */ +export class SessionManager { + private pageManager: PageManager; + + private applicationId: string; + private userExpiry: Date; + private sessionExpiry: Date; + private userId!: string; + private session: Session | undefined; + private config: Config; + private record: RecordSessionInitEvent; + private attributes: Attributes; + + constructor( + applicationId: string, + config: Config, + record: RecordSessionInitEvent, + pageManager: PageManager + ) { + this.applicationId = applicationId; + this.config = config; + this.record = record; + this.pageManager = pageManager; + this.session = undefined; + this.initializeUser(); + } + + /** + * Returns the session ID. If no session ID exists, one will be created. + */ + public getSession(): Session { + if (!this.session) { + // We do not store session attributes -- they must be collected for + // each new session. + this.collectAttributes(); + + // Try to restore the session from the session cookie. + this.getSessionFromCookie(); + } + + if (!this.session || new Date() > this.sessionExpiry) { + // The session does not exist or has expired. Create a new one. + this.createSession(); + } + + return this.session; + } + + public getAttributes(): Attributes { + return this.attributes; + } + + public getUserId(): string { + return this.userId; + } + + public incrementSessionEventCount() { + if (this.session) { + this.session.eventCount++; + this.renewSession(); + } + } + + private initializeUser() { + let userId: string = ''; + this.userExpiry = new Date(); + this.userExpiry.setDate( + this.userExpiry.getDate() + this.config.userIdRetentionDays + ); + + if (this.config.userIdRetentionDays <= 0) { + // Use the 'nil' UUID when the user ID will not be retained + this.userId = '00000000-0000-0000-0000-000000000000'; + } else if (this.useCookies()) { + userId = this.getUserIdCookie(); + this.userId = userId ? userId : v4(); + this.createOrRenewUserCookie(userId, this.userExpiry); + } else { + this.userId = v4(); + } + } + + private createOrRenewSessionCookie(session: Session, expires: Date) { + if (btoa) { + storeCookie( + SESSION_COOKIE_NAME, + btoa(JSON.stringify(session)), + undefined, + getCookieDomain(), + expires + ); + } + } + + private createOrRenewUserCookie(userId: string, expires: Date) { + storeCookie( + USER_COOKIE_NAME, + userId, + undefined, + getCookieDomain(), + expires + ); + } + + private getUserIdCookie() { + return getCookie(USER_COOKIE_NAME); + } + + private getSessionFromCookie() { + if (this.useCookies()) { + const cookie: string = getCookie(SESSION_COOKIE_NAME); + + if (cookie && atob) { + try { + this.session = JSON.parse(atob(cookie)); + this.pageManager.resumeSession( + this.session.page.pageId, + this.session.page.interaction + ); + } catch (e) { + // Error decoding or parsing the cookie -- ignore + } + } + } + } + + private storeSessionAsCookie() { + if (this.useCookies() && this.config.userIdRetentionDays > 0) { + this.createOrRenewUserCookie(this.userId, this.userExpiry); + } + + if (this.useCookies()) { + // Set the user cookie in case useCookies() has changed from false to true. + this.createOrRenewSessionCookie(this.session, this.sessionExpiry); + } + } + + private createSession() { + this.session = { + sessionId: v4(), + record: Math.random() < this.config.sessionSampleRate, + eventCount: 0 + }; + const pageViewEvent: PageViewEvent = this.pageManager.startSession(); + this.session.page = this.pageManager.getPage(); + this.sessionExpiry = new Date( + new Date().getTime() + this.config.sessionLengthSeconds * 1000 + ); + this.storeSessionAsCookie(); + this.record(this.session, SESSION_START_EVENT_TYPE, { + version: '1.0.0' + }); + this.record(this.session, PAGE_VIEW_TYPE, pageViewEvent); + } + + private renewSession() { + this.sessionExpiry = new Date( + new Date().getTime() + this.config.sessionLengthSeconds * 1000 + ); + this.session.page = this.pageManager.getPage(); + this.storeSessionAsCookie(); + } + + private collectAttributes() { + const ua = new UAParser(navigator.userAgent).getResult(); + this.attributes = { + browserLanguage: navigator.language, + browserName: ua.browser.name ? ua.browser.name : UNKNOWN, + browserVersion: ua.browser.version ? ua.browser.version : UNKNOWN, + osName: ua.os.name ? ua.os.name : UNKNOWN, + osVersion: ua.os.version ? ua.os.version : UNKNOWN, + // Possible device types include {console, mobile, tablet, smarttv, wearable, embedded}. If the device + // type is undefined, there was no information indicating the device is anything other than a desktop, + // so we assume the device is a desktop. + deviceType: ua.device.type ? ua.device.type : DESKTOP_DEVICE_TYPE, + // This client is used exclusively in web applications. + platformType: WEB_PLATFORM_TYPE, + domain: window.location.hostname + }; + } + + /** + * Returns true when cookies should be used to store user ID and session ID. + */ + private useCookies() { + return navigator.cookieEnabled && this.config.allowCookies; + } +} diff --git a/src/sessions/__integ__/PageManager.test.ts b/src/sessions/__integ__/PageManager.test.ts new file mode 100644 index 00000000..8c459999 --- /dev/null +++ b/src/sessions/__integ__/PageManager.test.ts @@ -0,0 +1,123 @@ +import { Selector } from 'testcafe'; +import { REQUEST_BODY } from '../../test-utils/integ-test-utils'; + +const recordPageView: Selector = Selector(`#recordPageView`); +const dispatch: Selector = Selector(`#dispatch`); +const clear: Selector = Selector(`#clearRequestResponse`); +const doNotRecordPageView = Selector(`#doNotRecordPageView`); + +fixture('PageViewEventPlugin').page('http://localhost:8080/page_event.html'); + +const removeUnwantedEvents = (json: any) => { + for (let i = 0; i < json.batch.events.length; i++) { + if (/(session_start_event)/.test(json.batch.events[i].type)) { + json.batch.events.splice(i, 1); + } + } + return json; +}; + +test('PageViewEventPlugin records page load event', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t + .wait(300) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const json = removeUnwantedEvents( + JSON.parse(await REQUEST_BODY.textContent) + ); + const eventType = json.batch.events[0].type; + const eventDetails = JSON.parse(json.batch.events[0].details); + const metaData = JSON.parse(json.batch.events[0].metadata); + + await t + .expect(eventType) + .eql('com.amazon.rum.page_view_event') + .expect(eventDetails) + .contains({ + pageId: '/page_event.html', + interaction: 0, + pageInteractionId: '/page_event.html-0' + }) + .expect(metaData) + .contains({ + url: 'http://localhost:8080/page_event.html', + pageId: '/page_event.html', + title: 'RUM Integ Test' + }); +}); + +test('PageViewEventPlugin records manual page view event', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + + await t + .wait(300) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch') + .click(clear) + .click(recordPageView) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const json = removeUnwantedEvents( + JSON.parse(await REQUEST_BODY.textContent) + ); + const eventType = json.batch.events[0].type; + const eventDetails = JSON.parse(json.batch.events[0].details); + const metaData = JSON.parse(json.batch.events[0].metadata); + + await t + .expect(eventType) + .eql('com.amazon.rum.page_view_event') + .expect(eventDetails) + .contains({ + pageId: '/page_view_two', + interaction: 1, + pageInteractionId: '/page_view_two-1', + parentPageInteractionId: '/page_event.html-0' + }) + .expect(metaData) + .contains({ + url: 'http://localhost:8080/page_event.html', + pageId: '/page_view_two', + title: 'RUM Integ Test' + }); +}); + +test('when page is denied then page view is not recorded', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + + await t + .wait(300) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch') + .click(clear) + .click(recordPageView) + .click(doNotRecordPageView) + .click(dispatch) + .expect(REQUEST_BODY.textContent) + .contains('batch'); + + const json = removeUnwantedEvents( + JSON.parse(await REQUEST_BODY.textContent) + ); + const eventDetails = JSON.parse(json.batch.events[0].details); + + await t + .expect(json.batch.events.length) + .eql(1) + .expect(eventDetails) + .contains({ + pageId: '/page_view_two', + interaction: 1, + pageInteractionId: '/page_view_two-1' + }); +}); diff --git a/src/sessions/__integ__/SessionManager.test.ts b/src/sessions/__integ__/SessionManager.test.ts new file mode 100644 index 00000000..2d400ce3 --- /dev/null +++ b/src/sessions/__integ__/SessionManager.test.ts @@ -0,0 +1,120 @@ +import { Selector } from 'testcafe'; +import { + STATUS_202, + BUTTON_ID_1, + DISPATCH_COMMAND, + COMMAND, + PAYLOAD, + SUBMIT, + REQUEST_BODY, + RESPONSE_STATUS +} from '../../test-utils/integ-test-utils'; +import { DOM_EVENT_PLUGIN_ID } from '../../plugins/event-plugins/DomEventPlugin'; + +import { SESSION_START_EVENT_TYPE } from '../SessionManager'; + +const randomSessionClickButton: Selector = Selector('#randomSessionClick'); +const disallowCookiesClickButton: Selector = Selector('#disallowCookies'); + +const BROWSER_LANGUAGE = 'browserLanguage'; +const BROWSER_NAME = 'browserName'; +const BROWSER_VERSION = 'browserVersion'; +const OS_NAME = 'osName'; +const OS_VERSION = 'osVersion'; +const DEVICE_TYPE = 'deviceType'; +const PLATFORM_TYPE = 'platformType'; + +const CONFIGURE_DOM_EVENT_PLUGIN_COMMAND = 'configurePlugin'; +const CONFIGURE_DOM_EVENT_PLUGIN_PAYLOAD = `{"pluginId": "${DOM_EVENT_PLUGIN_ID}", "config": [{"event":"click", "elementId":"button1"}]}`; + +const button1: Selector = Selector(`#${BUTTON_ID_1}`); + +fixture('Session Handler usage').page('http://localhost:8080/'); + +test('When cookies are enabled, sessionManager records events using cookies', async (t: TestController) => { + await t.wait(300); + + await t.click(randomSessionClickButton); + + await t.wait(300); + + await t + .typeText(COMMAND, DISPATCH_COMMAND, { replace: true }) + .click(PAYLOAD) + .pressKey('ctrl+a delete') + .click(SUBMIT); + + await t + .expect(REQUEST_BODY.textContent) + .contains(SESSION_START_EVENT_TYPE) + .expect(RESPONSE_STATUS.textContent) + .eql(STATUS_202.toString()); +}); + +test('When cookie is disabled, sessionManager records events using member variables', async (t: TestController) => { + await t.wait(300); + + await t.click(disallowCookiesClickButton); + + await t.wait(300); + + await t.click(randomSessionClickButton); + + await t.wait(300); + + await t + .typeText(COMMAND, DISPATCH_COMMAND, { replace: true }) + .click(PAYLOAD) + .pressKey('ctrl+a delete') + .click(SUBMIT); + + await t + .expect(REQUEST_BODY.textContent) + .contains(SESSION_START_EVENT_TYPE) + .expect(RESPONSE_STATUS.textContent) + .eql(STATUS_202.toString()); +}); + +test('UserAgentMetaDataPlugin records user agent metadata', async (t: TestController) => { + // If we click too soon, the client/event collector plugin will not be loaded and will not record the click. + // This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution. + await t.wait(300); + + // update configure, register click event for button1 + await t + .typeText(COMMAND, CONFIGURE_DOM_EVENT_PLUGIN_COMMAND, { + replace: true + }) + .typeText(PAYLOAD, CONFIGURE_DOM_EVENT_PLUGIN_PAYLOAD, { + replace: true + }) + .click(SUBMIT); + + // click button + await t.click(button1); + await t + .typeText(COMMAND, DISPATCH_COMMAND, { replace: true }) + .click(PAYLOAD) + .pressKey('ctrl+a delete') + .click(SUBMIT); + + // expect http request body contains user agent matedata + // expect http response with mock status code 202 + await t + .expect(REQUEST_BODY.textContent) + .contains(BROWSER_LANGUAGE) + .expect(REQUEST_BODY.textContent) + .contains(BROWSER_NAME) + .expect(REQUEST_BODY.textContent) + .contains(BROWSER_VERSION) + .expect(REQUEST_BODY.textContent) + .contains(OS_NAME) + .expect(REQUEST_BODY.textContent) + .contains(OS_VERSION) + .expect(REQUEST_BODY.textContent) + .contains(DEVICE_TYPE) + .expect(REQUEST_BODY.textContent) + .contains(PLATFORM_TYPE) + .expect(RESPONSE_STATUS.textContent) + .eql(STATUS_202.toString()); +}); diff --git a/src/sessions/__tests__/PageManager.test.ts b/src/sessions/__tests__/PageManager.test.ts new file mode 100644 index 00000000..5d468d55 --- /dev/null +++ b/src/sessions/__tests__/PageManager.test.ts @@ -0,0 +1,150 @@ +import { PageManager, PAGE_VIEW_TYPE } from '../PageManager'; +import { defaultConfig } from '../../orchestration/Orchestration'; + +const EXPECTED_ATTRIBUTES = { + title: 'Amazon AWS Console', + url: + 'https://us-east-1.console.aws.amazon.com/console/home?region=us-east-1#feedback', + pageId: '/glue/ajax', + parentPageId: '/console/home', + interaction: 1 +}; + +const EXPECTED_PAGE = { + pageId: '/console/home', + interaction: 0 +}; + +const EXPECTED_ON_SESSION_START = { + pageId: '/console/home', + interaction: 0 +}; + +const EXPECTED_ON_MANUAL = { + pageId: '/glue/ajax', + interaction: 1, + parentPageInteractionId: '/console/home-0' +}; + +const record = jest.fn(); + +Object.defineProperty(document, 'referrer', { + value: 'https://console.aws.amazon.com' +}); +Object.defineProperty(document, 'title', { value: 'Amazon AWS Console' }); + +describe('PageManager tests', () => { + let url; + + beforeAll(() => { + url = window.location.toString(); + }); + + beforeEach(() => { + record.mockClear(); + // @ts-ignore + jsdom.reconfigure({ + url: url + }); + }); + + test('When a session begins then PageManager returns a page view event.', async () => { + // Init + const pageManager: PageManager = new PageManager( + { + ...defaultConfig + }, + record + ); + + // Run + const pageViewEvent = pageManager.startSession(); + + // Assert + expect(pageViewEvent).toMatchObject(EXPECTED_ON_SESSION_START); + + // @ts-ignore + window.removeEventListener('popstate', pageManager.popstateListener); + }); + + test('When a page is manually recorded then PageManager records a page view event.', async () => { + // Init + const pageManager: PageManager = new PageManager( + { + ...defaultConfig + }, + record + ); + + // Run + pageManager.startSession(); + pageManager.recordPageView('/glue/ajax'); + + // Assert + expect(record.mock.calls[0][0]).toEqual(PAGE_VIEW_TYPE); + expect(record.mock.calls[0][1]).toMatchObject(EXPECTED_ON_MANUAL); + + // @ts-ignore + window.removeEventListener('popstate', pageManager.popstateListener); + }); + + test('getPage returns the current page', async () => { + // Init + const pageManager: PageManager = new PageManager( + { + ...defaultConfig + }, + record + ); + + // Run + pageManager.startSession(); + + // Assert + expect(pageManager.getPage()).toMatchObject(EXPECTED_PAGE); + + // @ts-ignore + window.removeEventListener('popstate', pageManager.popstateListener); + }); + + test('getAttributes returns the attributes for the current page', async () => { + // Init + const pageManager: PageManager = new PageManager( + { + ...defaultConfig + }, + record + ); + + // Run + pageManager.startSession(); + pageManager.recordPageView('/glue/ajax'); + + // Assert + expect(pageManager.getAttributes()).toMatchObject(EXPECTED_ATTRIBUTES); + + // @ts-ignore + window.removeEventListener('popstate', pageManager.popstateListener); + }); + + test('when pageIdFormat is not recognized then page ID defaults to PATH', async () => { + // Init + const pageManager: PageManager = new PageManager( + { + ...defaultConfig, + // @ts-ignore + pageIdFormat: 'PAGE_AND_HASH' + }, + record + ); + + // Run + const pageViewEvent = pageManager.startSession(); + + // Assert + expect(pageViewEvent).toMatchObject(EXPECTED_ON_SESSION_START); + + // @ts-ignore + window.removeEventListener('popstate', pageManager.popstateListener); + }); +}); diff --git a/src/sessions/__tests__/SessionManager.test.ts b/src/sessions/__tests__/SessionManager.test.ts new file mode 100644 index 00000000..538b925f --- /dev/null +++ b/src/sessions/__tests__/SessionManager.test.ts @@ -0,0 +1,586 @@ +// tslint:disable:max-line-length +import { + Attributes, + NIL_UUID, + SessionManager, + SESSION_START_EVENT_TYPE +} from '../SessionManager'; +import { + getCookie, + removeCookie, + storeCookie +} from '../../utils/cookies-utils'; +import * as uuid from 'uuid'; +import { navigationEvent } from '../../test-utils/mock-data'; +import { APPLICATION_ID } from '../../test-utils/test-utils'; +import { Config, defaultConfig } from '../../orchestration/Orchestration'; +import { mockRandom } from 'jest-mock-random'; +import { PageManager, PAGE_VIEW_TYPE } from '../PageManager'; +import { SESSION_COOKIE_NAME, USER_COOKIE_NAME } from '../../utils/constants'; + +const NAVIGATION = 'navigation'; +const SESSION_COOKIE_EXPIRES = 30 * 60; + +const MOBILE_USER_AGENT_META_DATA: Attributes = { + browserLanguage: 'en-US', + browserName: 'Mobile Safari', + browserVersion: '13.0.1', + osName: 'iOS', + osVersion: '13.1.3', + deviceType: 'mobile', + platformType: 'web', + domain: 'us-east-1.console.aws.amazon.com' +}; + +const MOBILE_USER_AGENT = + 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_1_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.1 Mobile/15E148 Safari/604.1'; + +const DESKTOP_USER_AGENT_META_DATA: Attributes = { + browserLanguage: 'en-US', + browserName: 'Chrome', + browserVersion: '20.0.1132.57', + osName: 'Mac OS', + osVersion: '10.7.3', + deviceType: 'desktop', + platformType: 'web', + domain: 'us-east-1.console.aws.amazon.com' +}; + +const DESKTOP_USER_AGENT = + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11'; + +const mockRecord = jest.fn(); + +const defaultSessionManager = (config) => { + return new SessionManager( + APPLICATION_ID, + config, + mockRecord, + new PageManager(config, mockRecord) + ); +}; + +describe('SessionManager tests', () => { + beforeEach(async () => { + window.performance.getEntriesByType = jest + .fn() + .mockImplementation((type) => { + if (type === NAVIGATION) { + return [navigationEvent]; + } + }); + + // cookie enabled + setNavigatorCookieEnabled(true); + + removeCookie(SESSION_COOKIE_NAME); + removeCookie(USER_COOKIE_NAME); + + mockRecord.mockClear(); + }); + + const setNavigatorCookieEnabled = (isEnabled: boolean) => { + Object.defineProperty(window.navigator, 'cookieEnabled', { + writable: true, + value: isEnabled + }); + }; + + test('When sessionId does not exist in cookie, then new sessionId is assigned', async () => { + // Init + const sessionManager = defaultSessionManager(defaultConfig); + const session = sessionManager.getSession(); + + // Assert + expect(sessionManager.getSession().sessionId).toEqual( + session.sessionId + ); + }); + + test('When sessionId exists in cookie, then it returns the existing sessionId', async () => { + // Init + const sessionId = uuid.v4(); + storeCookie( + SESSION_COOKIE_NAME, + btoa(JSON.stringify({ sessionId, record: true })), + SESSION_COOKIE_EXPIRES + ); + + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ allowCookies: true } + }); + + // Assert + expect(sessionManager.getSession().sessionId).toEqual(sessionId); + }); + + test('when sessionId cookie is corrupt then getSession returns a new sessionId', async () => { + // Init + const sessionId = uuid.v4(); + storeCookie(SESSION_COOKIE_NAME, sessionId, SESSION_COOKIE_EXPIRES); + + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ allowCookies: true } + }); + + // Run + const newSessionId: string = sessionManager.getSession().sessionId; + + // Assert + expect(newSessionId).toBeTruthy(); + expect(newSessionId).not.toEqual(sessionId); + }); + + test('When cookie is disabled, then sessionId is assigned from sessionManager', async () => { + // Init + setNavigatorCookieEnabled(false); + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ allowCookies: true } + }); + + // Assert + expect(sessionManager.getSession()).toBeTruthy(); + }); + + test('When allowCookies is denied, then sessionId is assigned from sessionManager', async () => { + // Init + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ allowCookies: true } + }); + + // Assert + expect(sessionManager.getSession()).toBeTruthy(); + }); + + test('when cookies are disabled after being enabled then sessionId remains the same', async () => { + // Init + const sessionId = uuid.v4(); + storeCookie( + SESSION_COOKIE_NAME, + btoa(JSON.stringify({ sessionId, record: true })), + SESSION_COOKIE_EXPIRES + ); + + const config: Config = { + ...defaultConfig, + ...{ allowCookies: true } + }; + const sessionManager = defaultSessionManager(config); + const sessionFromCookie = sessionManager.getSession(); + + // Assert + expect(sessionId).toEqual(sessionFromCookie.sessionId); + + // disallow + config.allowCookies = false; + + const sessionFromRumClient = sessionManager.getSession(); + + // Assert + expect(sessionFromRumClient.sessionId).toEqual( + sessionFromCookie.sessionId + ); + }); + + // start + test('When userId does not exist in cookie, then new userId is assigned', async () => { + // Init + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ userIdRetentionDays: 90 } + }); + const userId = sessionManager.getUserId(); + + // Assert + expect(sessionManager.getUserId()).toEqual(userId); + }); + + test('When userId exists in cookie, then it returns the same userId', async () => { + // Init + const userId = uuid.v4(); + storeCookie(USER_COOKIE_NAME, userId, SESSION_COOKIE_EXPIRES); + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ allowCookies: true, userIdRetentionDays: 90 } + }); + + // Assert + expect(sessionManager.getUserId()).toEqual(userId); + }); + + test('When cookie is disabled, then userId is assigned from sessionManager', async () => { + // Init + setNavigatorCookieEnabled(false); + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ userIdRetentionDays: 90 } + }); + + // Assert + expect(sessionManager.getUserId()).toBeTruthy(); + }); + + test('When allowCookies is denied, then userId is assigned from sessionManager', async () => { + // Init + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ allowCookies: true, userIdRetentionDays: 90 } + }); + + // Assert + expect(sessionManager.getUserId()).toBeTruthy(); + }); + + test('When cookie is disabled or enabled, then userId value is consistent', async () => { + // Init + const userId = uuid.v4(); + storeCookie(USER_COOKIE_NAME, userId, SESSION_COOKIE_EXPIRES); + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ allowCookies: true, userIdRetentionDays: 90 } + }); + + let userIdFromCookie = sessionManager.getUserId(); // get value from cookie + + // Assert + expect(userId).toEqual(userIdFromCookie); + + // disable cookie + setNavigatorCookieEnabled(false); + + const userIdFromRumClient = sessionManager.getUserId(); // has to get value from RUM web client + + // Assert + expect(userIdFromRumClient).toEqual(userIdFromCookie); + + // enableCookie + setNavigatorCookieEnabled(true); + + userIdFromCookie = sessionManager.getUserId(); + + // cookie and client should store same values + expect(userIdFromCookie).toEqual(userIdFromRumClient); + }); + + test('when cookies are disabled after being enabled then the userId remains the same', async () => { + // Init + const userId = uuid.v4(); + storeCookie(USER_COOKIE_NAME, userId, SESSION_COOKIE_EXPIRES); + const config: Config = { + ...defaultConfig, + ...{ allowCookies: true, userIdRetentionDays: 90 } + }; + const sessionManager = defaultSessionManager(config); + + // Run + const userIdFromCookie = sessionManager.getUserId(); + config.allowCookies = false; + const userIdFromRumClient = sessionManager.getUserId(); + + // Assert + expect(userId).toEqual(userIdFromCookie); + expect(userIdFromRumClient).toEqual(userIdFromCookie); + }); + + test('when the sessionId cookie expires then a new sessionId is created', async () => { + // Init + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ sessionLengthSeconds: 0, allowCookies: true } + }); + + const sessionOne = sessionManager.getSession(); + await new Promise((resolve) => setTimeout(resolve, 0)); + const sessionTwo = sessionManager.getSession(); + + // Assert + expect(sessionOne.sessionId).not.toEqual(sessionTwo.sessionId); + }); + + test('When the sessionId cookie does not expire, sessionId remains the same', async () => { + // Init + const config: Config = { + ...defaultConfig, + ...{ sessionLengthSeconds: 3600, allowCookies: true } + }; + const sessionManager = new SessionManager( + APPLICATION_ID, + config, + mockRecord, + new PageManager(config, mockRecord) + ); + + const sessionOne = sessionManager.getSession(); + const sessionTwo = sessionManager.getSession(); + + // Assert + expect(sessionOne.sessionId).toEqual(sessionTwo.sessionId); + }); + + test('when a new session starts then the session start event and page view event are emitted', async () => { + // init + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ allowCookies: true } + }); + + sessionManager.getSession(); + + // Assert + expect(mockRecord).toHaveBeenCalledTimes(2); + expect(mockRecord.mock.calls[0][1]).toEqual(SESSION_START_EVENT_TYPE); + expect(mockRecord.mock.calls[1][1]).toEqual(PAGE_VIEW_TYPE); + }); + + test('when a session is resumed then the session start event is not emitted', async () => { + // init + const sessionId = uuid.v4(); + storeCookie( + SESSION_COOKIE_NAME, + btoa( + JSON.stringify({ + sessionId, + record: true, + eventCount: 1, + page: { + pageId: '/console/home', + interaction: 1 + } + }) + ), + SESSION_COOKIE_EXPIRES + ); + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ allowCookies: true } + }); + + sessionManager.getSession(); + + // Assert + expect(mockRecord).toHaveBeenCalledTimes(1); + expect(mockRecord.mock.calls[0][0]).toEqual(PAGE_VIEW_TYPE); + }); + + test('when sessionSampleRate is one then session.record is true', async () => { + // Init + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ sessionSampleRate: 1, allowCookies: true } + }); + + const session = sessionManager.getSession(); + + // Assert + expect(session.record).toBeTruthy(); + }); + + test('when sessionSampleRate is zero then session.record is false', async () => { + // Init + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ sessionSampleRate: 0, allowCookies: true } + }); + + const session = sessionManager.getSession(); + + // Assert + expect(session.record).toBeFalsy(); + }); + + test('when random value equals sessionSampleRate then session.record is false', async () => { + // Init + mockRandom([0.5]); + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ sessionSampleRate: 0.5, allowCookies: true } + }); + + const session = sessionManager.getSession(); + + // Assert + expect(session.record).toBeFalsy(); + }); + + test('when when random value is less than sessionSampleRate then session.record is true', async () => { + // Init + mockRandom([0.4]); + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ sessionSampleRate: 0.5, allowCookies: true } + }); + + const session = sessionManager.getSession(); + + // Assert + expect(session.record).toBeTruthy(); + }); + + test('when random value is greater than sessionSampleRate then session.record is false', async () => { + // Init + mockRandom([0.6]); + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ sessionSampleRate: 0.5, allowCookies: true } + }); + + const session = sessionManager.getSession(); + + // Assert + expect(session.record).toBeFalsy(); + }); + + test('when getSession creates a new session then session.eventCount is zero', async () => { + // Init + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ allowCookies: true } + }); + + const session = sessionManager.getSession(); + + // Assert + expect(session.eventCount).toEqual(0); + }); + + test('when cookies are allowed then incrementSessionEventCount increments session.eventCount in cookie', async () => { + // Init + const sessionId = uuid.v4(); + storeCookie( + SESSION_COOKIE_NAME, + btoa(JSON.stringify({ sessionId, record: true, eventCount: 1 })), + SESSION_COOKIE_EXPIRES + ); + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ allowCookies: true } + }); + + // tslint:disable:no-empty + sessionManager.getSession(); + sessionManager.incrementSessionEventCount(); + const session = JSON.parse(atob(getCookie(SESSION_COOKIE_NAME))); + + // Assert + expect(session.eventCount).toEqual(2); + }); + + test('when cookies are not allowed then incrementSessionEventCount increments session.eventCount in member', async () => { + // Init + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ allowCookies: false } + }); + + sessionManager.getSession(); + sessionManager.incrementSessionEventCount(); + const session = sessionManager.getSession(); + + // Assert + expect(session.eventCount).toEqual(1); + }); + + test('session attributes include user agent', async () => { + // Init + Object.defineProperty(navigator, 'userAgent', { + get() { + return MOBILE_USER_AGENT; + }, + configurable: true + }); + + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ allowCookies: false } + }); + + // Run + sessionManager.getSession(); + const attributes: Attributes = sessionManager.getAttributes(); + + // Assert + expect(attributes).toEqual(MOBILE_USER_AGENT_META_DATA); + }); + + test("when user agent has no device type, then device type is 'desktop'", async () => { + // Init + Object.defineProperty(navigator, 'userAgent', { + get() { + return DESKTOP_USER_AGENT; + }, + configurable: true + }); + + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ allowCookies: false } + }); + + // Run + sessionManager.getSession(); + const attributes: Attributes = sessionManager.getAttributes(); + + // Assert + expect(attributes).toEqual(DESKTOP_USER_AGENT_META_DATA); + }); + + test('userIdRetentionDays defaults to zero and the the nil UUID', async () => { + // Init + const sessionManager = defaultSessionManager(defaultConfig); + + // Assert + expect(sessionManager.getUserId()).toEqual(NIL_UUID); + }); + + test('when userIdRetentionDays is zero then the user ID is the nil UUID', async () => { + // Init + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ userIdRetentionDays: 0 } + }); + + // Assert + expect(sessionManager.getUserId()).toEqual(NIL_UUID); + }); + + test('when userIdRetentionDays is zero then the user ID is not read from or written to a cookie', async () => { + // Init + const userId = uuid.v4(); + storeCookie(USER_COOKIE_NAME, userId, SESSION_COOKIE_EXPIRES); + + const sessionManager = defaultSessionManager({ + ...defaultConfig, + ...{ allowCookies: true, userIdRetentionDays: 0 } + }); + + const userIdFromCookie = getCookie(USER_COOKIE_NAME); + + // Assert + expect(sessionManager.getUserId()).toEqual(NIL_UUID); + expect(userId).toEqual(userIdFromCookie); + }); + + test('when cookies are enabled after initialization then renewing the session stores user ID cookie', async () => { + // Init + const config = { + ...defaultConfig, + ...{ allowCookies: false, userIdRetentionDays: 1 } + }; + + const sessionManager = defaultSessionManager(config); + + sessionManager.getSession(); + const userIdFromCookie1 = getCookie(USER_COOKIE_NAME); + config.allowCookies = true; + sessionManager.incrementSessionEventCount(); + const userIdFromCookie2 = getCookie(USER_COOKIE_NAME); + + // Assert + expect(userIdFromCookie1).toEqual(''); + expect(userIdFromCookie2).toEqual(sessionManager.getUserId()); + }); +}); diff --git a/src/test-utils/http-handler-utils.ts b/src/test-utils/http-handler-utils.ts new file mode 100644 index 00000000..dd70b2eb --- /dev/null +++ b/src/test-utils/http-handler-utils.ts @@ -0,0 +1,40 @@ +import { HttpRequest, HttpResponse } from '@aws-sdk/protocol-http'; +import { HeaderBag } from '@aws-sdk/types'; + +const setElementText = (name: string, text: string) => { + const element = document.getElementById(name); + if (element) { + element.textContent = text; + } +}; + +const headerBagToString = (headers: HeaderBag): string => { + let serial: string = ''; + let i = 0; + for (const key in headers) { + if (headers.hasOwnProperty(key)) { + if (i) { + serial += '; ' + key + '=' + headers[key]; + } else { + serial += key + '=' + headers[key]; + } + i++; + } + } + return serial; +}; + +export const logRequestToPage = (request: HttpRequest) => { + setElementText( + 'request_url', + request.protocol + '//' + request.hostname + request.path + ); + setElementText('request_header', headerBagToString(request.headers)); + setElementText('request_body', request.body); +}; + +export const logResponseToPage = (response: HttpResponse) => { + setElementText('response_status', response.statusCode.toString()); + setElementText('response_header', headerBagToString(response.headers)); + setElementText('response_body', response.body); +}; diff --git a/src/test-utils/integ-http-handler.ts b/src/test-utils/integ-http-handler.ts new file mode 100644 index 00000000..1acf2ec3 --- /dev/null +++ b/src/test-utils/integ-http-handler.ts @@ -0,0 +1,51 @@ +import { HttpHandler, HttpRequest, HttpResponse } from '@aws-sdk/protocol-http'; +import { FetchHttpHandler } from '../dispatch/FetchHttpHandler'; +import { HttpHandlerOptions } from '@aws-sdk/types'; +import { ClientBuilder } from '../dispatch/Dispatch'; +import { logRequestToPage, logResponseToPage } from './http-handler-utils'; +import { DataPlaneClient } from '../dispatch/DataPlaneClient'; +import { BeaconHttpHandler } from '../dispatch/BeaconHttpHandler'; + +/** + * Returns data plane service client with a request handler that intercepts + * requests/responses and prints them to an HTML table. + * @param endpoint Service endpoint. + * @param region Service region. + * @param credentials AWS credentials. + */ +export const showIntegRequestClientBuilder: ClientBuilder = ( + endpoint, + region, + credentials +) => { + return new DataPlaneClient({ + fetchRequestHandler: new ShowIntegRequestHandler( + new FetchHttpHandler({ fetchFunction: fetch }) + ), + beaconRequestHandler: new ShowIntegRequestHandler( + new BeaconHttpHandler() + ), + endpoint, + region, + credentials + }); +}; + +class ShowIntegRequestHandler implements HttpHandler { + handler: HttpHandler; + + constructor(handler: HttpHandler) { + this.handler = handler; + } + + handle( + request: HttpRequest, + options?: HttpHandlerOptions + ): Promise<{ response: HttpResponse }> { + logRequestToPage(request); + return this.handler.handle(request, options).then((response) => { + logResponseToPage(response.response); + return response; + }); + } +} diff --git a/src/test-utils/integ-test-utils.ts b/src/test-utils/integ-test-utils.ts new file mode 100644 index 00000000..167d46e0 --- /dev/null +++ b/src/test-utils/integ-test-utils.ts @@ -0,0 +1,23 @@ +import { Selector } from 'testcafe'; + +export const STATUS_202 = 202; +export const BUTTON_ID_1 = 'button1'; +export const BUTTON_ID_2 = 'button2'; +export const ID = 'id'; +export const TIMESTAMP = 'timestamp'; + +export const DISPATCH_COMMAND = 'dispatch'; +export const DISABLE_COMMAND = 'disable'; +export const ENABLE_COMMAND = 'enable'; + +export const COMMAND: Selector = Selector('#command'); +export const PAYLOAD: Selector = Selector('#payload'); +export const SUBMIT: Selector = Selector('#submit'); + +export const REQUEST_URL: Selector = Selector('#request_url'); +export const REQUEST_HEADER: Selector = Selector('#request_header'); +export const REQUEST_BODY: Selector = Selector('#request_body'); + +export const RESPONSE_STATUS: Selector = Selector('#response_status'); +export const RESPONSE_HEADER: Selector = Selector('#response_header'); +export const RESPONSE_BODY: Selector = Selector('#response_body'); diff --git a/src/test-utils/mock-data.ts b/src/test-utils/mock-data.ts new file mode 100644 index 00000000..a3aca9c4 --- /dev/null +++ b/src/test-utils/mock-data.ts @@ -0,0 +1,410 @@ +// tslint:disable:max-classes-per-file + +export const firstPaintEvent = { + name: 'first-paint', + duration: 0, + entryType: 'paint', + startTime: 306.44000000029337 +}; + +export const firstContentfulPaintEvent = { + name: 'first-contentful-paint', + duration: 0, + entryType: 'paint', + startTime: 306.44000000029337 +}; + +export const navigationEvent = { + connectEnd: 6.495000001450535, + connectStart: 6.495000001450535, + decodedBodySize: 149690, + domComplete: 904.4250000006286, + domContentLoadedEventEnd: 405.5950000001758, + domContentLoadedEventStart: 380.26000000172644, + domInteractive: 380.2250000007916, + domainLookupEnd: 6.495000001450535, + domainLookupStart: 6.495000001450535, + duration: 905.125000001135, + encodedBodySize: 35941, + entryType: 'navigation', + fetchStart: 6.495000001450535, + initiatorType: 'navigation', + loadEventEnd: 905.125000001135, + loadEventStart: 904.4549999998708, + name: + 'https://stackoverflow.com/questions/53224116/nodejs-performance-hooks-crash-when-calling-performance-getentriesbytype', + nextHopProtocol: 'h2', + redirectCount: 0, + redirectEnd: 0, + redirectStart: 0, + requestStart: 30.170000001817243, + responseEnd: 356.44999999931315, + responseStart: 174.32499999995343, + secureConnectionStart: 6.495000001450535, + serverTiming: [], + startTime: 0, + transferSize: 36525, + type: 'navigate', + unloadEventEnd: 0, + unloadEventStart: 0, + workerStart: 0, + navigationTimingLevel: 2 +}; + +export const resourceEvent = { + connectEnd: 0, + connectStart: 0, + decodedBodySize: 0, + domainLookupEnd: 0, + domainLookupStart: 0, + duration: 438.39999999909196, + encodedBodySize: 0, + entryType: 'resource', + fetchStart: 357.59500000131084, + initiatorType: 'script', + name: + 'https://www.gravatar.com/avatar/47a91063fb01317639d57d5fc9c9d9c7?s=32&d=identicon&r=PG', + nextHopProtocol: 'h2', + redirectEnd: 0, + redirectStart: 0, + requestStart: 0, + responseEnd: 795.9950000004028, + responseStart: 0, + secureConnectionStart: 0, + serverTiming: [], + startTime: 357.59500000131084, + transferSize: 0, + workerStart: 0 +}; + +export const resourceEvent2 = { + connectEnd: 386.37999998172745, + connectStart: 386.37999998172745, + decodedBodySize: 79, + domainLookupEnd: 386.37999998172745, + domainLookupStart: 386.37999998172745, + duration: 2.640000020619482, + encodedBodySize: 79, + entryType: 'resource', + fetchStart: 386.37999998172745, + initiatorType: 'script', + name: 'http://localhost:9000/sockjs-node/info?t=1616810767123', + nextHopProtocol: 'http/1.1', + redirectEnd: 0, + redirectStart: 0, + requestStart: 388.2449999800883, + responseEnd: 389.02000000234693, + responseStart: 388.71499997912906, + secureConnectionStart: 0, + serverTiming: [], + startTime: 386.37999998172745, + transferSize: 368, + workerStart: 0 +}; + +export const dataPlaneResourceEvent = { + connectEnd: 0, + connectStart: 0, + decodedBodySize: 0, + domainLookupEnd: 0, + domainLookupStart: 0, + duration: 438.39999999909196, + encodedBodySize: 0, + entryType: 'resource', + fetchStart: 357.59500000131084, + initiatorType: 'link', + name: + 'https://dataplane.us-west-2.beta.rum.aws.dev/application/aa17a42c-e737-48f7-adaf-2e0905f48073/events', + nextHopProtocol: 'h2', + redirectEnd: 0, + redirectStart: 0, + requestStart: 0, + responseEnd: 795.9950000004028, + responseStart: 0, + secureConnectionStart: 0, + serverTiming: [], + startTime: 357.59500000131084, + transferSize: 0, + workerStart: 0 +}; + +export const scriptResourceEvent = { + connectEnd: 386.37999998172745, + connectStart: 386.37999998172745, + decodedBodySize: 79, + domainLookupEnd: 386.37999998172745, + domainLookupStart: 386.37999998172745, + duration: 2.640000020619482, + encodedBodySize: 79, + entryType: 'resource', + fetchStart: 386.37999998172745, + initiatorType: 'script', + name: 'http://localhost:9000/main.js', + nextHopProtocol: 'http/1.1', + redirectEnd: 0, + redirectStart: 0, + requestStart: 388.2449999800883, + responseEnd: 389.02000000234693, + responseStart: 388.71499997912906, + secureConnectionStart: 0, + serverTiming: [], + startTime: 386.37999998172745, + transferSize: 368, + workerStart: 0 +}; + +export const imageResourceEvent = { + connectEnd: 386.37999998172745, + connectStart: 386.37999998172745, + decodedBodySize: 79, + domainLookupEnd: 386.37999998172745, + domainLookupStart: 386.37999998172745, + duration: 2.640000020619482, + encodedBodySize: 79, + entryType: 'resource', + fetchStart: 386.37999998172745, + initiatorType: 'script', + name: 'http://localhost:9000/picture.jpg', + nextHopProtocol: 'http/1.1', + redirectEnd: 0, + redirectStart: 0, + requestStart: 388.2449999800883, + responseEnd: 389.02000000234693, + responseStart: 388.71499997912906, + secureConnectionStart: 0, + serverTiming: [], + startTime: 386.37999998172745, + transferSize: 368, + workerStart: 0 +}; + +export const cssResourceEvent = { + connectEnd: 386.37999998172745, + connectStart: 386.37999998172745, + decodedBodySize: 79, + domainLookupEnd: 386.37999998172745, + domainLookupStart: 386.37999998172745, + duration: 2.640000020619482, + encodedBodySize: 79, + entryType: 'resource', + fetchStart: 386.37999998172745, + initiatorType: 'script', + name: 'http://localhost:9000/style.css', + nextHopProtocol: 'http/1.1', + redirectEnd: 0, + redirectStart: 0, + requestStart: 388.2449999800883, + responseEnd: 389.02000000234693, + responseStart: 388.71499997912906, + secureConnectionStart: 0, + serverTiming: [], + startTime: 386.37999998172745, + transferSize: 368, + workerStart: 0 +}; + +export interface ObserveInterface { + type: string; + buffered: boolean; +} + +const entries = [navigationEvent, resourceEvent]; + +export class MockPerformanceObserver { + static simulateErrorOnObserve = false; + + constructor(cb: any) { + (this as any).observe = (options: ObserveInterface) => { + if (MockPerformanceObserver.simulateErrorOnObserve) { + MockPerformanceObserver.simulateErrorOnObserve = false; + throw new Error('Simulated Error'); + } + cb({ getEntries: () => [...entries] }); + return {}; + }; + } +} + +export const MockPerformanceTiming: PerformanceTiming = { + connectEnd: 1618335687913, + connectStart: 1618335687836, + domComplete: 1618335688379, + domContentLoadedEventEnd: 1618335688365, + domContentLoadedEventStart: 1618335688365, + domInteractive: 1618335688268, + domLoading: 1618335688091, + domainLookupEnd: 1618335687836, + domainLookupStart: 1618335687836, + fetchStart: 1618335687836, + loadEventEnd: 1618335688383, + loadEventStart: 1618335688379, + navigationStart: 1618335687836, + redirectEnd: 0, + redirectStart: 0, + requestStart: 1618335687914, + responseEnd: 1618335688210, + responseStart: 1618335688078, + secureConnectionStart: 1618335687847, + unloadEventEnd: 0, + unloadEventStart: 0, + toJSON: () => ({}) +}; + +export class MockEmptyPerformanceObserver { + constructor(cb: any) { + (this as any).observe = (options: ObserveInterface) => { + return cb({ getEntries: () => [] }); + }; + } +} + +export const performanceEvent = { + performance: () => { + delete (window as any).performance; + const performance = { + getEntriesByType: (entryType: string) => { + if (entryType === 'navigation') { + return [navigationEvent]; + } + + if (entryType === 'resource') { + return [resourceEvent2]; + } + + if (entryType === 'paint') { + return [firstPaintEvent, firstContentfulPaintEvent]; + } + return []; + }, + now: () => { + return Date.now(); + }, + timing: MockPerformanceTiming + }; + Object.defineProperty(window, 'performance', { + configurable: true, + enumerable: true, + value: performance, + writable: true + }); + return window.performance; + }, + PerformanceObserver: MockPerformanceObserver +}; + +export const mockPerformanceObject = () => { + delete (window as any).performance; + const performanceObject = { + getEntriesByType: (entryType: string) => { + if (entryType === 'resource') { + return [dataPlaneResourceEvent]; + } + if (entryType === 'paint') { + return []; + } + return []; + }, + now: () => { + return Date.now(); + }, + timing: MockPerformanceTiming + }; + Object.defineProperty(window, 'performance', { + configurable: true, + enumerable: true, + value: performanceObject, + writable: true + }); +}; + +export const mockPerformanceObjectWithResources = () => { + delete (window as any).performance; + const performanceObject = { + getEntriesByType: (entryType: string) => { + if (entryType === 'resource') { + return [ + scriptResourceEvent, + imageResourceEvent, + cssResourceEvent + ]; + } + if (entryType === 'paint') { + return []; + } + return []; + }, + now: () => { + return Date.now(); + }, + timing: MockPerformanceTiming + }; + Object.defineProperty(window, 'performance', { + configurable: true, + enumerable: true, + value: performanceObject, + writable: true + }); +}; + +export const mockPaintPerformanceObject = () => { + delete (window as any).performance; + const performanceObject = { + getEntriesByType: (entryType: string) => { + if (entryType === 'resource') { + return [resourceEvent]; + } + if (entryType === 'paint') { + return []; + } + if (entryType === 'navigation') { + return [navigationEvent]; + } + return []; + }, + now: () => { + return Date.now(); + }, + timing: MockPerformanceTiming + }; + Object.defineProperty(window, 'performance', { + configurable: true, + enumerable: true, + value: performanceObject, + writable: true + }); +}; + +export class MockPaintPerformanceObserver { + static simulateErrorOnObserve = false; + + constructor(cb: any) { + (this as any).observe = (options: ObserveInterface) => { + if (MockPerformanceObserver.simulateErrorOnObserve) { + MockPerformanceObserver.simulateErrorOnObserve = false; + throw new Error('Simulated Error'); + } + cb({ getEntries: () => [resourceEvent2] }); + return {}; + }; + } +} + +export const mockPaintPerformanceObserver = () => { + (window as any).PerformanceObserver = MockPaintPerformanceObserver; +}; + +export const mockPerformanceObserver = () => { + (window as any).PerformanceObserver = MockEmptyPerformanceObserver; +}; + +export const httpErrorEvent = { + version: '1.0.0', + eventType: 'ERROR', + name: 'HTTP', + method: 'POST', + statusCode: 400, + statusText: 'Bad Request', + responseURL: + 'https://jtrm21au2a.execute-api.us-west-2.amazonaws.com/alpha/v1.0.0/putBatchMetrics', + responseText: '{"message":"Could not persist data"}' +}; diff --git a/src/test-utils/mock-http-handler.ts b/src/test-utils/mock-http-handler.ts new file mode 100644 index 00000000..1c4eb401 --- /dev/null +++ b/src/test-utils/mock-http-handler.ts @@ -0,0 +1,40 @@ +import { HttpHandler, HttpRequest, HttpResponse } from '@aws-sdk/protocol-http'; +import { ClientBuilder } from '../dispatch/Dispatch'; +import { DataPlaneClient } from '../dispatch/DataPlaneClient'; +import { logRequestToPage, logResponseToPage } from './http-handler-utils'; + +/** + * Returns data plane service client with a mocked request handler. + * @param endpoint Service endpoint. + * @param region Service region. + * @param credentials AWS credentials. + */ +export const showRequestClientBuilder: ClientBuilder = ( + endpoint, + region, + credentials +) => { + return new DataPlaneClient({ + fetchRequestHandler: new ShowMockRequestHandler(), + beaconRequestHandler: new ShowMockRequestHandler(), + endpoint, + region, + credentials + }); +}; + +class ShowMockRequestHandler implements HttpHandler { + handle(request: HttpRequest): Promise<{ response: HttpResponse }> { + const response: HttpResponse = { + statusCode: 202, + headers: { + 'content-type': 'application/json', + 'Access-Control-Allow-Origin': '*' + }, + body: undefined + }; + logRequestToPage(request); + logResponseToPage(response); + return Promise.resolve({ response }); + } +} diff --git a/src/test-utils/test-utils.ts b/src/test-utils/test-utils.ts new file mode 100644 index 00000000..2cfeca5b --- /dev/null +++ b/src/test-utils/test-utils.ts @@ -0,0 +1,128 @@ +import { EventCache } from '../event-cache/EventCache'; +import { Credentials } from '@aws-sdk/types'; +import { Config, defaultConfig } from '../orchestration/Orchestration'; +import { + GetSession, + PluginContext, + RecordEvent, + RecordPageView +} from '../plugins/Plugin'; +import { + ApplicationDetails, + LogEventsRequest, + UserDetails +} from '../dispatch/dataplane'; +import { ReadableStream } from 'web-streams-polyfill'; + +export const AWS_RUM_ENDPOINT = + 'https://rumservicelambda.us-west-2.amazonaws.com'; +export const AWS_RUM_REGION = 'us-west-2'; +export const APPLICATION_ID = 'application123'; +export const APPLICATION_VERSION = '1.2'; +export const BATCH_ID = 'batch123'; +export const USER_ID = 'user123'; +export const SESSION_ID = 'session123'; +export const AUTO_DISPATCH_OFF = 0; + +export const EVENT_ID = 'event123'; +export const EVENT_TYPE = 'com.amazon.rum.event1'; +export const EVENT_DETAILS = '{}'; +export const EVENT_TIMESTAMP = new Date(0); + +export const APPLICATION_DETAILS: ApplicationDetails = { + name: APPLICATION_ID, + version: APPLICATION_VERSION +}; + +export const USER_DETAILS: UserDetails = { + userId: USER_ID, + sessionId: SESSION_ID +}; + +export const LOG_EVENTS_REQUEST: LogEventsRequest = { + applicationId: APPLICATION_ID, + batch: { + batchId: BATCH_ID, + application: APPLICATION_DETAILS, + user: USER_DETAILS, + events: [ + { + id: EVENT_ID, + timestamp: EVENT_TIMESTAMP, + type: EVENT_TYPE, + details: EVENT_DETAILS + } + ] + } +}; + +export const createDefaultEventCache = (): EventCache => { + return new EventCache(APPLICATION_DETAILS, defaultConfig); +}; + +export const createEventCache = (config: Config): EventCache => { + return new EventCache(APPLICATION_DETAILS, config); +}; + +export const createDefaultEventCacheWithEvents = (): EventCache => { + const EVENT1_SCHEMA = 'com.amazon.rum.event1'; + const EVENT2_SCHEMA = 'com.amazon.rum.event2'; + const eventCache = new EventCache(APPLICATION_DETAILS, defaultConfig); + eventCache.recordEvent(EVENT1_SCHEMA, {}); + eventCache.recordEvent(EVENT2_SCHEMA, {}); + return eventCache; +}; + +export const createAwsCredentials = (): Credentials => { + return { + accessKeyId: 'abc123', + secretAccessKey: 'abc123xyz' + }; +}; + +export const createAwsError = () => { + return { + name: 'error-code', + code: 'error-code', + message: 'Something went wrong.', + statusCode: 500, + time: new Date() + }; +}; + +export const sleep = (ms: number) => { + return new Promise((resolve) => setTimeout(resolve, ms)); +}; + +export const record: jest.MockedFunction = jest.fn(); +export const recordPageView: jest.MockedFunction = jest.fn(); +export const getSession: jest.MockedFunction = jest.fn(() => ({ + sessionId: 'abc123', + record: true, + eventCount: 0 +})); +export const context: PluginContext = { + applicationName: 'a', + applicationId: 'b', + applicationVersion: '1.0', + config: defaultConfig, + record, + recordPageView, + getSession +}; + +export const stringToUtf16 = (inputString: string) => { + const utf16array = []; + for (let index = 0; index < inputString.length; index++) { + utf16array[index] = inputString.charCodeAt(index); + } + return utf16array; +}; + +export const getReadableStream = (mockString: string) => + new ReadableStream({ + start(c) { + c.enqueue(stringToUtf16(mockString)); + c.close(); + } + }); diff --git a/src/utils/__tests__/common-utils.test.ts b/src/utils/__tests__/common-utils.test.ts new file mode 100644 index 00000000..f1aa2ea4 --- /dev/null +++ b/src/utils/__tests__/common-utils.test.ts @@ -0,0 +1,63 @@ +import * as utils from '../../utils/common-utils'; + +describe('Common utils tests', () => { + test('When URL has "png" file extension then return file type as "image"', async () => { + // Init + const resourceUrl = + 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png'; + // Assert + expect(utils.getResourceFileType(resourceUrl)).toEqual( + utils.ResourceType.IMAGE + ); + }); + + test('When URL has "js" file extension then return file type as "script"', async () => { + // Init + const resourceUrl = + 'https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js'; + // Assert + expect(utils.getResourceFileType(resourceUrl)).toEqual( + utils.ResourceType.SCRIPT + ); + }); + + test('When URL has no file extension then return file type as "other"', async () => { + // Init + const resourceUrl = + 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRTOllsWmffF4hRvZr8ZgQwv4oHKC_Kyksu39SAuqnZ-5OjnwQBGDNojmfu0C8&usqp=CAQ&s=10'; + // Assert + expect(utils.getResourceFileType(resourceUrl)).toEqual( + utils.ResourceType.OTHER + ); + }); + + test('When URL has "css" file extension then return file type as "stylesheet"', async () => { + // Init + const resourceUrl = + 'https://cdn.sstatic.net/Shared/stacks.css?v=f0ad20c3c35c'; + // Assert + expect(utils.getResourceFileType(resourceUrl)).toEqual( + utils.ResourceType.STYLESHEET + ); + }); + + test('When URL has "html" file extension then return file type as "document"', async () => { + // Init + const resourceUrl = + 'https://tpc.googlesyndication.com/sodar/sodar2/222/runner.html'; + // Assert + expect(utils.getResourceFileType(resourceUrl)).toEqual( + utils.ResourceType.DOCUMENT + ); + }); + + test('When URL has "woff" file extension then return file type as "font"', async () => { + // Init + const resourceUrl = + 'https://dco-assets.everestads.net/ics-campaign//5031/t/8417/1/Base/fonts/SegoePro-Semibold.woff'; + // Assert + expect(utils.getResourceFileType(resourceUrl)).toEqual( + utils.ResourceType.FONT + ); + }); +}); diff --git a/src/utils/__tests__/cookies-utils.test.ts b/src/utils/__tests__/cookies-utils.test.ts new file mode 100644 index 00000000..643eb713 --- /dev/null +++ b/src/utils/__tests__/cookies-utils.test.ts @@ -0,0 +1,171 @@ +import * as utils from '../../utils/cookies-utils'; + +const COOKIE_FRE_FIX = 'rum_cookies_util_test'; + +describe('Cookies utils tests', () => { + test('storeCookie()', async () => { + // Init + const cookieName = COOKIE_FRE_FIX + '_' + new Date().getTime(); + const cookieValue = new Date().toString(); + + // Run + utils.storeCookie(cookieName, cookieValue); + + // Assert + expect(document.cookie).toEqual(cookieName + '=' + cookieValue); + + // Cleanup + document.cookie = + cookieName + '=; Expires=Thu, 01 Jan 1970 00:00:01 GMT'; + }); + + test('when storeCookie() given ttl=0 then cookie immediately expires', async () => { + // Init + const cookieName = COOKIE_FRE_FIX + '_' + new Date().getTime(); + const cookieValue = 'value'; + + // Run + utils.storeCookie(cookieName, cookieValue, 0); + + // Assert + expect(document.cookie).toBeFalsy(); + + // Cleanup + document.cookie = + cookieName + '=; Expires=Thu, 01 Jan 1970 00:00:01 GMT'; + }); + + test('when storeCookie() given ttl > 0 then cookie does not immediately expire', async () => { + // Init + const cookieName = COOKIE_FRE_FIX + '_' + new Date().getTime(); + const cookieValue = 'value'; + + // Run + utils.storeCookie(cookieName, cookieValue, 3600); + + // Assert + expect(document.cookie).toBeTruthy(); + + // Cleanup + document.cookie = + cookieName + '=; Expires=Thu, 01 Jan 1970 00:00:01 GMT'; + }); + + test('getCookie() when document.cookie has only one cookie, return the correct cookie value', async () => { + // Init + const cookieName = COOKIE_FRE_FIX + '_' + new Date().getTime(); + const cookieValue = new Date().toString(); + document.cookie = cookieName + '=' + cookieValue; + + // Assert + expect(utils.getCookie(cookieName)).toEqual(cookieValue); + + // Cleanup + document.cookie = + cookieName + '=; Expires=Thu, 01 Jan 1970 00:00:01 GMT'; + }); + + test('getCookie() when document.cookie has more than one cookie, return the correct cookie value', async () => { + // Init + const cookieName1 = COOKIE_FRE_FIX + '_' + new Date().getTime(); + const cookieValue1 = new Date().toString(); + + const cookieName2 = COOKIE_FRE_FIX + '_' + new Date().getTime(); + const cookieValue2 = new Date().toString(); + + document.cookie = + cookieName1 + + '=' + + cookieValue1 + + '; ' + + cookieName2 + + '=' + + cookieValue2; + + // Assert + expect(utils.getCookie(cookieName1)).toEqual(cookieValue1); + expect(utils.getCookie(cookieName2)).toEqual(cookieValue2); + + // Cleanup + document.cookie = + cookieName1 + '=; Expires=Thu, 01 Jan 1970 00:00:01 GMT'; + document.cookie = + cookieName2 + '=; Expires=Thu, 01 Jan 1970 00:00:01 GMT'; + }); + + test('removeCookie()', async () => { + // Init + const cookieName = COOKIE_FRE_FIX + '_' + new Date().getTime(); + const cookieValue = new Date().toString(); + document.cookie = cookieName + '=' + cookieValue; + + // Run + utils.removeCookie(cookieName); + + // Assert + expect(document.cookie).toEqual(''); + }); + + test('getCookieDomain() with root domain returns root domain', async () => { + jest.spyOn(utils, 'storeCookie').mockImplementation( + ( + name: string, + value: string, + expires?: number, + domain?: string + ) => { + if (domain && domain === 'amazon.com') { + document.cookie = name + '=' + value; + } + } + ); + + // Init + document.domain = 'amazon.com'; + + // Assert + expect(utils.getCookieDomain()).toEqual('amazon.com'); + }); + + test('getCookieDomain() returns a root domain when given a sub-domain', async () => { + jest.spyOn(utils, 'storeCookie').mockImplementation( + ( + name: string, + value: string, + expires?: number, + domain?: string + ) => { + if (domain && domain === 'amazon.com') { + document.cookie = name + '=' + value; + } + } + ); + + // Init + document.domain = 'docs.aws.amazon.com'; + + // Assert + expect(utils.getCookieDomain()).toEqual('amazon.com'); + }); + + test('getCookieDomain() returns localhost when given localhost domain', async () => { + jest.spyOn(utils, 'storeCookie').mockImplementation( + ( + name: string, + value: string, + expires?: number, + domain?: string + ) => { + if (domain && domain === 'localhost') { + document.cookie = name + '=' + value; + } + } + ); + + // Init + document.domain = 'localhost'; + + // Assert + expect(utils.getCookieDomain()).toEqual('localhost'); + }); +}); diff --git a/src/utils/common-utils.ts b/src/utils/common-utils.ts new file mode 100644 index 00000000..be257dc1 --- /dev/null +++ b/src/utils/common-utils.ts @@ -0,0 +1,167 @@ +export enum ResourceType { + OTHER = 'other', + STYLESHEET = 'stylesheet', + DOCUMENT = 'document', + SCRIPT = 'script', + IMAGE = 'image', + FONT = 'font' +} + +const extensions = [ + { + name: ResourceType.STYLESHEET, + list: ['css', 'less'] + }, + { + name: ResourceType.DOCUMENT, + list: ['htm', 'html', 'ts', 'doc', 'docx', 'pdf', 'xls', 'xlsx'] + }, + { + name: ResourceType.SCRIPT, + list: ['js'] + }, + { + name: ResourceType.IMAGE, + list: [ + 'ai', + 'bmp', + 'gif', + 'ico', + 'jpeg', + 'jpg', + 'png', + 'ps', + 'psd', + 'svg', + 'tif', + 'tiff' + ] + }, + { + name: ResourceType.FONT, + list: ['fnt', 'fon', 'otf', 'ttf', 'woff'] + } +]; + +export const shuffle = (a: any[]) => { + for (let i = a.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + const v = a[i]; + a[i] = a[j]; + a[j] = v; + } +}; + +export const getResourceFileType = (url: string): ResourceType => { + const filename = url.substring(url.lastIndexOf('/') + 1); + const extension = filename + .substring(filename.lastIndexOf('.') + 1) + .split(/[?#]/)[0]; + + let ext = ResourceType.OTHER; + extensions.forEach((type) => { + if (type.list.indexOf(extension) > -1) { + ext = type.name; + } + }); + return ext; +}; + +export const getPath = (path: string | undefined): string => { + if (path === undefined) { + return ''; + } + const uriPathPattern = /^([^?#]*)(\?([^#]*))?(#(.*))?/; + const pathMatch = path.match(uriPathPattern); + if (!pathMatch || !pathMatch[1]) { + return ''; + } + return pathMatch[1]; +}; + +export const getQuery = (path: string | undefined): string => { + if (path === undefined) { + return ''; + } + const uriPathPattern = /^([^?#]*)(\?([^#]*))?(#(.*))?/; + const pathMatch = path.match(uriPathPattern); + if (!pathMatch || !pathMatch[2]) { + return ''; + } + return pathMatch[2]; +}; + +export const getFragment = (path: string | undefined): string => { + if (path === undefined) { + return ''; + } + const uriPathPattern = /^([^?#]*)(\?([^#]*))?(#(.*))?/; + const pathMatch = path.match(uriPathPattern); + if (!pathMatch || !pathMatch[4]) { + return ''; + } + return pathMatch[4]; +}; + +export const getHost = (url: string): string => { + const urlPattern = /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/; + const match = url.match(urlPattern); + if (!match || !match[4]) { + return ''; + } + return match[4]; +}; + +export const getScheme = (url: string): string => { + const urlPattern = /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/; + const match = url.match(urlPattern); + if (!match || !match[2]) { + return ''; + } + return match[2]; +}; + +/* Helpers */ +export const httpStatusText = { + '0': 'Abort Request', + '200': 'OK', + '201': 'Created', + '202': 'Accepted', + '203': 'Non-Authoritative Information', + '204': 'No Content', + '205': 'Reset Content', + '206': 'Partial Content', + '300': 'Multiple Choices', + '301': 'Moved Permanently', + '302': 'Found', + '303': 'See Other', + '304': 'Not Modified', + '305': 'Use Proxy', + '306': 'Unused', + '307': 'Temporary Redirect', + '400': 'Bad Request', + '401': 'Unauthorized', + '402': 'Payment Required', + '403': 'Forbidden', + '404': 'Not Found', + '405': 'Method Not Allowed', + '406': 'Not Acceptable', + '407': 'Proxy Authentication Required', + '408': 'Request Timeout', + '409': 'Conflict', + '410': 'Gone', + '411': 'Length Required', + '412': 'Precondition Required', + '413': 'Request Entry Too Large', + '414': 'Request-URI Too Long', + '415': 'Unsupported Media Type', + '416': 'Requested Range Not Satisfiable', + '417': 'Expectation Failed', + '418': 'I"m a teapot', + '500': 'Internal Server Error', + '501': 'Not Implemented', + '502': 'Bad Gateway', + '503': 'Service Unavailable', + '504': 'Gateway Timeout', + '505': 'HTTP Version Not Supported' +}; diff --git a/src/utils/constants.ts b/src/utils/constants.ts new file mode 100644 index 00000000..0ea559e2 --- /dev/null +++ b/src/utils/constants.ts @@ -0,0 +1,3 @@ +export const CRED_COOKIE_NAME = 'cwr_c'; +export const SESSION_COOKIE_NAME = 'cwr_s'; +export const USER_COOKIE_NAME = 'cwr_u'; diff --git a/src/utils/cookies-utils.ts b/src/utils/cookies-utils.ts new file mode 100644 index 00000000..6648ed88 --- /dev/null +++ b/src/utils/cookies-utils.ts @@ -0,0 +1,86 @@ +/** + * Stores a cookie. + * @param name The cookie's name. + * @param value The cookie's value. + * @param ttl Time to live -- expiry date is current date + ttl (do not use with {@code expires}). + * @param domain The domain where the cookie will be stored. + * @param expires The expiry date for the cookie (do not use with {@code ttl}) + */ +export const storeCookie = ( + name: string, + value: string, + ttl?: number, + domain?: string, + expires?: Date +) => { + let cookie = name + '='; + cookie += value || ''; + if (expires !== undefined) { + cookie += + expires !== undefined ? '; Expires=' + expires.toUTCString() : ''; + } else if (ttl !== undefined) { + cookie += '; Expires=' + getExpiryDate(ttl).toUTCString(); + } + cookie += '; SameSite=Strict; Secure'; + cookie += domain ? '; Domain=' + domain : ''; + document.cookie = cookie; +}; + +/** + * Returns the current date + TTL + * @param ttl seconds to live + */ +export const getExpiryDate = (ttl: number): Date => { + return new Date(new Date().getTime() + ttl * 1000); +}; + +/** + * Removes a cookie by setting its expiry in the past. + * @param name The cookie's name. + */ +export const removeCookie = (name: string, domain?: string) => { + document.cookie = + name + + '=; Expires=' + + new Date(0) + + '; SameSite=Strict; Secure' + + (domain ? '; Domain=' + domain : ''); +}; + +/** + * Get a cookie with a given name + * @param name The cookie's name. + */ +export const getCookie = (name: string): string => { + const cookies = document.cookie.split('; '); + for (const cookie of cookies) { + const split = cookie.split('='); + if (split[0] === name) { + return split[1]; + } + } + return ''; +}; + +/** + * Finds the highest level (non-top-level) domain that can be used to store cookies. + */ +export const getCookieDomain = (): string => { + if (!document.domain) { + return ''; + } + const subdomain = document.domain.split('.'); + for ( + let i = subdomain.length - 1, ts = Date.now().toString(); + i >= 0; + i-- + ) { + const cookieDomain = subdomain.slice(i).join('.'); + storeCookie(ts, ts, undefined, cookieDomain); + if (getCookie(ts)) { + removeCookie(ts, cookieDomain); + return cookieDomain; + } + } + return document.domain; +}; diff --git a/src/utils/random.ts b/src/utils/random.ts new file mode 100644 index 00000000..26bf0b90 --- /dev/null +++ b/src/utils/random.ts @@ -0,0 +1,13 @@ +declare var msCrypto: + | undefined + | { getRandomValues: (holder: Uint8Array) => Uint8Array }; + +export const getRandomValues = (holder: Uint8Array): Uint8Array => { + if (crypto) { + return crypto.getRandomValues(holder); + } else if (msCrypto) { + return msCrypto.getRandomValues(holder); + } else { + throw new Error('No crypto library found.'); + } +}; diff --git a/tsconfig.cjs.json b/tsconfig.cjs.json new file mode 100644 index 00000000..0e4d8e36 --- /dev/null +++ b/tsconfig.cjs.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "baseUrl": "src", + "declaration": true, + "lib": ["dom", "es2018"], + "module": "commonjs", + "moduleResolution": "node", + "strict": true, + "strictPropertyInitialization": false, + "target": "es5", + "outDir": "./dist/cjs" + }, + "include": ["src/"], + "exclude": [ + "**/__tests__", + "**/__integ__", + "**/__mocks__", + "src/index-browser.ts", + "src/loader", + "src/test-utils" + ] +} diff --git a/tsconfig.es.json b/tsconfig.es.json new file mode 100644 index 00000000..24f44363 --- /dev/null +++ b/tsconfig.es.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "baseUrl": "src", + "declaration": true, + "lib": ["dom", "es2018"], + "module": "esnext", + "moduleResolution": "node", + "strict": true, + "strictPropertyInitialization": false, + "target": "es5", + "outDir": "./dist/es" + }, + "include": ["src/"], + "exclude": [ + "**/__tests__", + "**/__integ__", + "**/__mocks__", + "src/index-browser.ts", + "src/loader", + "src/test-utils" + ] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..ff325013 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "baseUrl": "src", + "declaration": true, + "lib": ["dom", "es2018"], + "module": "esnext", + "moduleResolution": "node", + "strict": true, + "strictPropertyInitialization": false + }, + "include": ["src/"], + "exclude": [ + "**/__tests__", + "**/__integ__", + "**/__mocks__", + "src/index-browser.ts", + "src/loader", + "src/test-utils" + ] +} diff --git a/tsconfig.unit.json b/tsconfig.unit.json new file mode 100644 index 00000000..f12e35b2 --- /dev/null +++ b/tsconfig.unit.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "baseUrl": "src", + "downlevelIteration": true, + "esModuleInterop": true, + "lib": ["es2018", "dom"], + "moduleResolution": "node", + "noEmit": true, + "target": "es2018", + "types": ["node", "jest", "@testing-library/jest-dom"] + }, + "include": ["types", "**/__tests__/**/*.ts", "**/__mocks__/**/*.ts"] +} diff --git a/tsconfig.webpack.json b/tsconfig.webpack.json new file mode 100644 index 00000000..5933622d --- /dev/null +++ b/tsconfig.webpack.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "baseUrl": "src", + "lib": ["dom", "es2018"], + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "target": "es5", + "outDir": "./dist/webpack" + }, + "include": ["src/"], + "exclude": [ + "**/__tests__", + "**/__integ__", + "**/__mocks__", + "src/index.ts", + "src/loader", + "src/test-utils" + ] +} diff --git a/tslint.json b/tslint.json new file mode 100644 index 00000000..633eee42 --- /dev/null +++ b/tslint.json @@ -0,0 +1,32 @@ +{ + "extends": ["tslint:recommended", "tslint-config-prettier"], + "linterOptions": { + "exclude": ["node_modules/**"] + }, + "rules": { + "array-type": [true, "array"], + "arrow-parens": false, + "arrow-return-shorthand": true, + "import-name": false, + "interface-name": [true, "never-prefix"], + "interface-over-type-literal": false, + "member-access": false, + "max-line-length": [ + true, + { + "limit": 120, + "ignore-pattern": "^import |^export {(.*?)}" + } + ], + "member-ordering": [ + true, + { + "order": "fields-first" + } + ], + "no-shadowed-variable": false, + "object-literal-sort-keys": false, + "only-arrow-functions": true, + "ordered-imports": false + } +} diff --git a/webpack/webpack.common.js b/webpack/webpack.common.js new file mode 100644 index 00000000..6d2f5b7f --- /dev/null +++ b/webpack/webpack.common.js @@ -0,0 +1,9 @@ +const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); + +module.exports = { + entry: './src/index-browser.ts', + resolve: { + extensions: ['.ts', '.js', '.json'] + }, + plugins: [new CaseSensitivePathsPlugin()] +}; diff --git a/webpack/webpack.dev.js b/webpack/webpack.dev.js new file mode 100644 index 00000000..8cb27232 --- /dev/null +++ b/webpack/webpack.dev.js @@ -0,0 +1,59 @@ +const CopyWebpackPlugin = require('copy-webpack-plugin'); +const common = require('./webpack.common'); +const merge = require('webpack-merge'); +const path = require('path'); + +module.exports = merge(common, { + mode: 'development', + devtool: 'inline-source-map', + entry: { + rum_javascript_telemetry: './src/index-browser.ts', + loader_standard: './src/loader/loader-standard.js', + loader_page_event: './src/loader/loader-page-event.js', + loader_dom_event: './src/loader/loader-dom-event.js', + loader_js_error_event: './src/loader/loader-js-error-event.js', + loader_http_fetch_event: './src/loader/loader-http-fetch-event.js', + loader_http_xhr_event: './src/loader/loader-http-xhr-event.js', + loader_web_vital_event: './src/loader/loader-web-vital-event.js', + loader_cookies_enabled: './src/loader/loader-cookies-enabled.js', + loader_cookies_disabled: './src/loader/loader-cookies-disabled.js', + loader_pre_load_command_queue_test: + './src/loader/loader-pre-load-command-queue-test.js', + loader_post_load_command_queue_test: + './src/loader/loader-post-load-command-queue-test.js' + }, + resolve: { + extensions: ['.ts', '.js', '.json'] + }, + output: { + path: path.join(__dirname, '../build/dev'), + filename: '[name].js' + }, + devServer: { + contentBase: path.join(__dirname, '../build/dev'), + port: 9000, + https: false, + hot: true + }, + module: { + rules: [ + { + test: [/\.ts$/], + exclude: /node_modules/, + use: [ + { + loader: 'ts-loader', + options: { + configFile: 'tsconfig.webpack.json' + } + } + ] + } + ] + }, + plugins: [ + new CopyWebpackPlugin({ + patterns: [{ from: 'app' }] + }) + ] +}); diff --git a/webpack/webpack.prod.js b/webpack/webpack.prod.js new file mode 100644 index 00000000..e7f2e42b --- /dev/null +++ b/webpack/webpack.prod.js @@ -0,0 +1,67 @@ +const path = require('path'); +const merge = require('webpack-merge'); +const common = require('./webpack.common'); +const LicensePlugin = require('webpack-license-plugin'); + +const babelLoaderOptions = { + presets: [ + [ + '@babel/preset-env', + { + targets: { + browsers: [ + 'last 3 chrome versions', + 'last 3 firefox versions', + 'ie 11', + 'last 3 edge versions', + 'last 3 safari versions' + ] + } + } + ] + ] +}; + +module.exports = merge(common, { + plugins: [new LicensePlugin()], + mode: 'production', + devtool: 'nosources-source-map', + optimization: { + minimizer: [ + new TerserPlugin({ + parallel: true, + extractComments: true + }) + ] + }, + output: { + path: path.join(__dirname, '../build/assets'), + filename: 'cwr.js' + }, + module: { + rules: [ + { + test: [/.js$/], + use: { + loader: 'babel-loader', + options: babelLoaderOptions + } + }, + { + test: [/\.ts$/], + use: [ + { + loader: 'babel-loader', + options: babelLoaderOptions + }, + { + loader: 'ts-loader', + options: { + configFile: 'tsconfig.webpack.json' + } + } + ] + } + ] + } +});