├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── bank ├── app-sns.js └── app.js ├── cdk.json ├── cdk ├── LoanBroker-PubSub-stack.ts ├── LoanBroker-RecipientList-stack.ts ├── aws-cdk-loan-broker-app.ts └── integration-patterns.ts ├── credit-bureau └── app.js ├── package-lock.json ├── package.json ├── quote-aggregator └── app.js ├── quote-requester └── app.js └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | !jest.config.js 2 | *.d.ts 3 | node_modules 4 | 5 | # CDK asset staging directory 6 | .cdk.staging 7 | cdk.out 8 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Loan Broker with AWS CDK 2 | 3 | This project is an AWS Cloud Development Kit (CDK) implementation of Gregor Hohpe's [Loan Broker example](https://www.enterpriseintegrationpatterns.com/ramblings/loanbroker_stepfunctions.html). 4 | 5 | The purpose is to show how serverless orchestration with integration patterns could be implemented with [CDK](https://aws.amazon.com/cdk). 6 | 7 | ## Table of content 8 | - [Overview](#overview) 9 | - [Loan Broker implementations](#loan-broker-implementations) 10 | * [Recipient List](#recipient-list) 11 | * [Publish Subscribe](#publish-subscribe) 12 | - [Usage](#usage) 13 | * [Bootstrap your environment](#bootstrap-your-environment) 14 | * [Install dependencies](#install-dependencies) 15 | * [Initial deployment](#initial-deployment) 16 | * [Pre-populate LoanBrokerBanksTable for RecipientsList stack](#pre-populate-loanbrokerbankstable-for-recipientslist-stack) 17 | * [Execute loan broker request](#execute-loan-broker-request) 18 | * [Destroy the stacks](#destroy-the-stacks) 19 | - [Security](#security) 20 | - [License](#license) 21 | 22 | ## Overview 23 | 24 | The example application demonstrates a basic integration scenario, which consists of several steps: 25 | 1. A Customer submits a loan application with personal data and desired terms, such as loan amount and duration. 26 | 2. The Loan Broker enriches the request with the customer's credit score retrieved from the Credit Bureau. 27 | 3. The Loan Broker submits the application to multiple Banks. 28 | 4. The Banks reply with a loan offer if they are willing to service the loan. 29 | 5. The Loan Broker aggregates the results, for example by selecting the best offer. 30 | 6. The Loan Broker returns the result(s) to the Customer. 31 | 32 | ![Loan Broker - Overview](https://www.enterpriseintegrationpatterns.com/img/ConsumerLoanBroker.gif) 33 | 34 | 35 | ## Loan Broker implementations 36 | ### Recipient List 37 | 38 | [This version](lib/LoanBroker-RecipientList-stack.ts) uses the [Recipient List](https://www.enterpriseintegrationpatterns.com/patterns/messaging/RecipientList.html) pattern, meaning the Loan Broker first retrieves a list of banks to request quotes from. 39 | For more details, see [here](https://www.enterpriseintegrationpatterns.com/ramblings/loanbroker_stepfunctions.html). 40 | 41 | ![Recipient List - Architecture overview](https://www.enterpriseintegrationpatterns.com/img/step-function-recipient-list.png) 42 | 43 | ### Publish Subscribe 44 | In order to be able to dynamically route loan application to multiple banks [this version](lib/LoanBroker-PubSub-stack.ts) uses the [Scatter Gather](https://www.enterpriseintegrationpatterns.com/patterns/messaging/RecipientList.html) pattern, meaning the Loan Broker does not require to know upfront how many banks there are or how they are implemented. 45 | For more details, see [here](https://www.enterpriseintegrationpatterns.com/ramblings/loanbroker_stepfunctions_pubsub.html). 46 | 47 | ![Scatter Gather - Architecture overview](https://www.enterpriseintegrationpatterns.com/img/step-function-pub-sub-summary.png) 48 | 49 | 50 | ## Usage 51 | ### Bootstrap your environment 52 | ``` 53 | cdk bootstrap aws://ACCOUNT-NUMBER/REGION # e.g. cdk bootstrap aws://123456789012/us-east-1 54 | ``` 55 | 56 | For more details, see [AWS Cloud Development Kit](https://docs.aws.amazon.com/cdk/latest/guide/bootstrapping.html). 57 | 58 | ### Install dependencies 59 | ``` 60 | npm install 61 | ``` 62 | 63 | ### Initial deployment 64 | ``` 65 | cdk deploy LoanBroker-RecipientList-Stack 66 | cdk deploy LoanBroker-PubSub-Stack 67 | ``` 68 | 69 | ### Pre-populate LoanBrokerBanksTable for RecipientsList stack 70 | ``` 71 | aws dynamodb put-item \ 72 | --table-name=LoanBrokerBanksTable \ 73 | --item='{ "Type": { "S": "Home" }, "BankAddress": {"L": [ { "S": "BankRecipientPremium" }, { "S": "BankRecipientUniversal" }, { "S": "BankRecipientPawnshop" } ] } }' 74 | ``` 75 | 76 | ### Execute loan broker request 77 | 78 | In order to start the state machine, execute: 79 | ``` 80 | aws stepfunctions start-execution \ 81 | --name=cli-test-run \ 82 | --state-machine-arn=STATE_MACHINE_ARN \ 83 | --input="{\"SSN\": \"123-45-6789\", \"Amount\": 500000, \"Term\": 30 }" 84 | ``` 85 | 86 | You can use the resulting state machine ARN that is included in the CDK output. 87 | 88 | The result contains the execution ARN, that is needed to request the output, e.g: 89 | ``` 90 | { 91 | "executionArn": "STATE_MACHINE_ARN:cli-test-run", 92 | "startDate": "2021-12-01T13:37:00.000000+00:00" 93 | } 94 | ``` 95 | 96 | To see the output of the state machine execution, execute this: 97 | ``` 98 | aws stepfunctions describe-execution \ 99 | --execution-arn=STATE_MACHINE_ARN:cli-test-run \ 100 | --query="output" | jq -r '. | fromjson' 101 | ``` 102 | 103 | This will result in: 104 | ``` 105 | { 106 | "Credit": { "Score": 693, "History": 24 }, 107 | "Amount": 600000, 108 | "Quotes": [ 109 | { "rate": 5.271301238502866, "bankId": "Universal" }, 110 | { "rate": 3.8970175730277457, "bankId": "Premium" } 111 | ], 112 | "Term": 30, 113 | "SSN": "123-45-6789" 114 | } 115 | ``` 116 | 117 | 118 | 119 | 120 | ### Destroy the stacks 121 | ``` 122 | cdk destroy --all 123 | ``` 124 | 125 | 126 | ## Security 127 | 128 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. 129 | 130 | ## License 131 | 132 | This project is licensed under the Apache-2.0 License. 133 | 134 | -------------------------------------------------------------------------------- /bank/app-sns.js: -------------------------------------------------------------------------------- 1 | /** 2 | Each bank will vary its behavior by the following parameters: 3 | 4 | MIN_CREDIT_SCORE - the customer's minimum credit score required to receive a quote from this bank. 5 | MAX_LOAN_AMOUNT - the maximum amount the bank is willing to lend to a customer. 6 | BASE_RATE - the minimum rate the bank might give. The actual rate increases for a lower credit score and some randomness. 7 | BANK_ID - as the loan broker processes multiple responses, knowing which bank supplied the quote will be handy. 8 | */ 9 | 10 | function calcRate(amount, term, score, history) { 11 | if (amount <= process.env.MAX_LOAN_AMOUNT && score >= process.env.MIN_CREDIT_SCORE) { 12 | return parseFloat(process.env.BASE_RATE) + Math.random() * ((1000 - score) / 100.0); 13 | } 14 | } 15 | 16 | exports.handler = async (event, context) => { 17 | console.log("Received request for %s", process.env.BANK_ID); 18 | console.log("Received event:", JSON.stringify(event, null, 4)); 19 | 20 | console.log(event.Records[0].Sns); 21 | const snsMessage = event.Records[0].Sns.Message; 22 | const msg = JSON.parse(snsMessage); 23 | console.debug(msg.input); 24 | 25 | const requestId = msg.context.Execution.Id; 26 | const taskToken = msg.taskToken; 27 | const bankId = process.env.BANK_ID; 28 | const data = msg.input; 29 | 30 | console.log("Loan Request over %d at credit score %d", data.Amount, data.Credit.Score); 31 | const rate = calcRate(data.Amount, data.Term, data.Credit.Score, data.Credit.History); 32 | 33 | if (rate) { 34 | const quote = { 35 | rate: rate, 36 | bankId: bankId, 37 | id: requestId, 38 | taskToken: taskToken, 39 | }; 40 | console.log("Offering Loan", quote); 41 | 42 | return quote; 43 | } else { 44 | console.log("Rejecting Loan"); 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /bank/app.js: -------------------------------------------------------------------------------- 1 | /** 2 | Each bank will vary its behavior by the following parameters: 3 | 4 | MIN_CREDIT_SCORE - the customer's minimum credit score required to receive a quote from this bank. 5 | MAX_LOAN_AMOUNT - the maximum amount the bank is willing to lend to a customer. 6 | BASE_RATE - the minimum rate the bank might give. The actual rate increases for a lower credit score and some randomness. 7 | BANK_ID - as the loan broker processes multiple responses, knowing which bank supplied the quote will be handy. 8 | */ 9 | 10 | function calcRate(amount, term, score, history) { 11 | if (amount <= process.env.MAX_LOAN_AMOUNT && score >= process.env.MIN_CREDIT_SCORE) { 12 | return parseFloat(process.env.BASE_RATE) + Math.random() * ((1000 - score) / 100.0); 13 | } 14 | } 15 | 16 | exports.handler = async (event) => { 17 | console.log("Received request for %s", process.env.BANK_ID); 18 | console.log("Received event:", JSON.stringify(event, null, 4)); 19 | 20 | const amount = event.Amount; 21 | const term = event.Term; 22 | const score = event.Credit.Score; 23 | const history = event.Credit.History; 24 | 25 | const bankId = process.env.BANK_ID; 26 | 27 | console.log("Loan Request over %d at credit score %d", amount, score); 28 | const rate = calcRate(amount, term, score, history); 29 | if (rate) { 30 | const response = { rate: rate, bankId: bankId }; 31 | console.log(response); 32 | return response; 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node --prefer-ts-exts cdk/aws-cdk-loan-broker-app.ts", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "**/*.d.ts", 11 | "**/*.js", 12 | "tsconfig.json", 13 | "package*.json", 14 | "yarn.lock", 15 | "node_modules", 16 | "test" 17 | ] 18 | }, 19 | "context": { 20 | "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, 21 | "@aws-cdk/core:stackRelativeExports": true, 22 | "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, 23 | "@aws-cdk/aws-lambda:recognizeVersionProps": true, 24 | "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /cdk/LoanBroker-PubSub-stack.ts: -------------------------------------------------------------------------------- 1 | import * as path from "path"; 2 | 3 | import { CfnOutput, Duration, RemovalPolicy, Stack, StackProps } from "aws-cdk-lib"; 4 | import { Construct } from "constructs"; 5 | import { SnsEventSource, SqsEventSource } from "aws-cdk-lib/aws-lambda-event-sources"; 6 | import { EventBus } from "aws-cdk-lib/aws-events"; 7 | import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs"; 8 | import * as destinations from "aws-cdk-lib/aws-lambda-destinations"; 9 | import * as dynamodb from "aws-cdk-lib/aws-dynamodb"; 10 | import * as lambda from "aws-cdk-lib/aws-lambda"; 11 | import * as logs from "aws-cdk-lib/aws-logs"; 12 | import * as sfn from "aws-cdk-lib/aws-stepfunctions"; 13 | import * as sns from "aws-cdk-lib/aws-sns"; 14 | import * as sqs from "aws-cdk-lib/aws-sqs"; 15 | import * as tasks from "aws-cdk-lib/aws-stepfunctions-tasks"; 16 | import {ContentFilter, MessageFilter, MessageContentFilter} from "./integration-patterns"; 17 | 18 | 19 | /** 20 | * Environment as specified by the lambda.Function environment 21 | */ 22 | class environment { 23 | [key: string]: string; 24 | } 25 | 26 | 27 | /** 28 | * Interface for the bank function environment. 29 | * It contains all the necessary environment variables for the bank functionality. 30 | */ 31 | interface BankFunctionEnvironment extends environment { 32 | BANK_ID: string; 33 | BASE_RATE: string; 34 | MAX_LOAN_AMOUNT: string; 35 | MIN_CREDIT_SCORE: string; 36 | } 37 | 38 | 39 | /** 40 | * CDK Stack implementation of the Loan broker pub sub, 41 | * see https://www.enterpriseintegrationpatterns.com/ramblings/loanbroker_stepfunctions_pubsub.html 42 | */ 43 | export class LoanBrokerPubSubStack extends Stack { 44 | constructor(scope: Construct, id: string, props?: StackProps) { 45 | super(scope, id, props); 46 | 47 | 48 | // Set up credit bureau lambda 49 | const creditBureauLambda = new lambda.Function(this, "CreditBureauLambda", { 50 | runtime: lambda.Runtime.NODEJS_18_X, 51 | handler: "app.handler", 52 | code: lambda.Code.fromAsset("credit-bureau"), 53 | functionName: "CreditBureauLambda-PubSub", 54 | }); 55 | 56 | // Setup get credit score from credit bureau task 57 | const getCreditScoreFromCreditBureau = new tasks.LambdaInvoke(this, "Get Credit Score from credit bureau", { 58 | lambdaFunction: creditBureauLambda, 59 | payload: sfn.TaskInput.fromObject({ 60 | "SSN.$": "$.SSN", 61 | "RequestId.$": "$$.Execution.Id", 62 | }), 63 | resultPath: "$.Credit", 64 | resultSelector: { 65 | "Score.$": "$.Payload.body.score", 66 | "History.$": "$.Payload.body.history", 67 | }, 68 | retryOnServiceExceptions: false, // This is just for development purposes 69 | }); 70 | 71 | // Setup mortgage event bus, to route mortgage quotes 72 | const mortgageQuotesEventBus = new EventBus(this, "MortgageQuotesEventBus", { 73 | eventBusName: "MortgageQuotesEventBus", 74 | }); 75 | 76 | const mortgageQuotesQueue = new sqs.Queue(this, "MortgageQuotesQueue", { 77 | retentionPeriod: Duration.minutes(5), 78 | 79 | removalPolicy: RemovalPolicy.DESTROY, // This is just for development purposes 80 | }); 81 | 82 | // Setup message and content filter for mortgage quotes 83 | var nonEmptyQuoteMessageFilter = MessageFilter.fieldExists(this, "nonEmptyQuoteMessageFilter", "bankId"); 84 | var payloadContentFilter = ContentFilter.createPayloadFilter(this, "PayloadContentFilter"); 85 | 86 | new MessageContentFilter(this, "FilterMortgageQuotes", { 87 | sourceEventBus: mortgageQuotesEventBus, 88 | targetQueue: mortgageQuotesQueue, 89 | messageFilter: nonEmptyQuoteMessageFilter, 90 | contentFilter: payloadContentFilter, 91 | }); 92 | 93 | // Set up the different banks 94 | const bankRecipientPawnshop = this._createBankFunction({ 95 | bankName: "BankRecipientPawnshop", 96 | destinationEventBus: mortgageQuotesEventBus, 97 | bankConfiguration: { 98 | BANK_ID: "PawnShop", 99 | BASE_RATE: "5", 100 | MAX_LOAN_AMOUNT: "500000", 101 | MIN_CREDIT_SCORE: "400", 102 | }, 103 | }); 104 | 105 | const bankRecipientUniversal = this._createBankFunction({ 106 | bankName: "BankRecipientUniversal", 107 | destinationEventBus: mortgageQuotesEventBus, 108 | bankConfiguration: { 109 | BANK_ID: "Universal", 110 | BASE_RATE: "4", 111 | MAX_LOAN_AMOUNT: "700000", 112 | MIN_CREDIT_SCORE: "500", 113 | }, 114 | }); 115 | 116 | const bankRecipientPremium = this._createBankFunction({ 117 | bankName: "BankRecipientPremium", 118 | destinationEventBus: mortgageQuotesEventBus, 119 | bankConfiguration: { 120 | BANK_ID: "Premium", 121 | BASE_RATE: "3", 122 | MAX_LOAN_AMOUNT: "900000", 123 | MIN_CREDIT_SCORE: "600", 124 | }, 125 | }); 126 | 127 | // Set up the mortgage quote request topic 128 | const mortgageQuoteRequestTopic = new sns.Topic(this, "MortgageQuoteRequest", { 129 | displayName: "MortgageQuoteRequest topic", 130 | }); 131 | 132 | // Add all banks to the mortgage quote request topic 133 | [bankRecipientPawnshop, bankRecipientUniversal, bankRecipientPremium] 134 | .forEach((bank) => { 135 | bank.addEventSource(new SnsEventSource(mortgageQuoteRequestTopic)); 136 | }); 137 | 138 | // Setup mortgage quotes table 139 | const mortgageQuotesTable = new dynamodb.Table(this, "MortgageQuotesTable", { 140 | partitionKey: { name: "Id", type: dynamodb.AttributeType.STRING }, 141 | billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, 142 | tableName: "MortgageQuotesTable", 143 | 144 | removalPolicy: RemovalPolicy.DESTROY, // This is just for development purposes 145 | }); 146 | 147 | // Set up quote aggregator lambda 148 | const quoteAggregatorLambda = new NodejsFunction(this, "QuoteAggregatorLambda", { 149 | runtime: lambda.Runtime.NODEJS_18_X, 150 | handler: "handler", 151 | entry: path.join(__dirname, "../quote-aggregator/app.js"), 152 | functionName: "QuoteAggregator", 153 | environment: { 154 | MORTGAGE_QUOTES_TABLE: mortgageQuotesTable.tableName, 155 | }, 156 | }); 157 | 158 | quoteAggregatorLambda.addEventSource( 159 | new SqsEventSource(mortgageQuotesQueue, { 160 | batchSize: 10, 161 | }) 162 | ); 163 | 164 | mortgageQuotesQueue.grantConsumeMessages(quoteAggregatorLambda); 165 | mortgageQuotesTable.grantWriteData(quoteAggregatorLambda); 166 | 167 | // Request mortgage quotes from all banks custom state (get function name at runtime from state input is currently not natively supported by the CDK) 168 | const requestMortgageQuotesFromAllBanks = new tasks.SnsPublish(this, "Request mortgage quotes from all banks", { 169 | topic: mortgageQuoteRequestTopic, 170 | message: sfn.TaskInput.fromObject({ 171 | taskToken: sfn.JsonPath.taskToken, 172 | input: sfn.JsonPath.entirePayload, 173 | context: sfn.JsonPath.entireContext, 174 | }), 175 | resultPath: "$.Quotes", 176 | integrationPattern: sfn.IntegrationPattern.WAIT_FOR_TASK_TOKEN, 177 | 178 | timeout: Duration.seconds(5), 179 | }); 180 | 181 | const getMortgageQuotesLambda = new NodejsFunction(this, "GetMortgageQuotesLambda", { 182 | runtime: lambda.Runtime.NODEJS_18_X, 183 | handler: "handler", 184 | entry: path.join(__dirname, "../quote-requester/app.js"), 185 | functionName: "QuoteRequester", 186 | environment: { 187 | MORTGAGE_QUOTES_TABLE: mortgageQuotesTable.tableName, 188 | }, 189 | }); 190 | mortgageQuotesTable.grantReadData(getMortgageQuotesLambda); 191 | 192 | // TODO: Replace with DynamoDB Get Item call 193 | // Setup get mortgage quotes task 194 | const getMortgageQuotes = new tasks.LambdaInvoke(this, "Get Mortgage Quotes", { 195 | lambdaFunction: getMortgageQuotesLambda, 196 | payload: sfn.TaskInput.fromObject({ 197 | "Id.$": "$$.Execution.Id", 198 | }), 199 | resultPath: "$.result", 200 | resultSelector: { 201 | "Quotes.$": "$.Payload.quotes", 202 | }, 203 | 204 | retryOnServiceExceptions: false, // This is just for development purposes 205 | }); 206 | 207 | // Setup transformation of the result 208 | const transformMortgageQuotesResponse = new sfn.Pass(this, "Transform Mortgage Quotes Response", { 209 | parameters: { 210 | "SSN.$": "$.SSN", 211 | "Amount.$": "$.Amount", 212 | "Term.$": "$.Term", 213 | "Credit.$": "$.Credit", 214 | "Quotes.$": "$.result.Quotes", 215 | }, 216 | }); 217 | 218 | const loanBrokerDefinition = 219 | getCreditScoreFromCreditBureau 220 | .next(requestMortgageQuotesFromAllBanks 221 | .addCatch(getMortgageQuotes 222 | .next(transformMortgageQuotesResponse), 223 | { 224 | errors: ["States.Timeout"], 225 | resultPath: "$.Error", 226 | } 227 | ) 228 | ); 229 | 230 | const loanBrokerLogGroup = new logs.LogGroup(this, "LoanBrokerLogGroup"); 231 | 232 | const loanBroker = new sfn.StateMachine(this, "LoanBroker", { 233 | definitionBody: sfn.DefinitionBody.fromChainable(loanBrokerDefinition), 234 | 235 | stateMachineType: sfn.StateMachineType.STANDARD, 236 | timeout: Duration.minutes(5), 237 | logs: { 238 | destination: loanBrokerLogGroup, 239 | level: sfn.LogLevel.ALL, 240 | includeExecutionData: true, 241 | }, 242 | tracingEnabled: true, 243 | }); 244 | 245 | mortgageQuoteRequestTopic.grantPublish(loanBroker); 246 | loanBroker.grantTaskResponse(quoteAggregatorLambda); 247 | 248 | new CfnOutput(this, "LoanBrokerArn", { 249 | value: loanBroker.stateMachineArn, 250 | }); 251 | } 252 | 253 | /** 254 | * Creates a bank lambda function. 255 | * 256 | * @param name Name of the bank 257 | * @param env The environment configurations of the bank 258 | * @para 259 | * @returns A bank Lambda function 260 | */ 261 | private _createBankFunction(config: { 262 | bankName: string; 263 | bankConfiguration: BankFunctionEnvironment; 264 | destinationEventBus: EventBus; 265 | }) { 266 | return new lambda.Function(this, config.bankName, { 267 | runtime: lambda.Runtime.NODEJS_18_X, 268 | handler: "app-sns.handler", 269 | code: lambda.Code.fromAsset("bank"), 270 | functionName: config.bankName + "-PubSub", 271 | environment: config.bankConfiguration, 272 | 273 | onSuccess: new destinations.EventBridgeDestination(config.destinationEventBus), 274 | }); 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /cdk/LoanBroker-RecipientList-stack.ts: -------------------------------------------------------------------------------- 1 | import { CfnOutput, Duration, RemovalPolicy, Stack, StackProps } from "aws-cdk-lib"; 2 | import { Construct } from "constructs"; 3 | import * as dynamodb from "aws-cdk-lib/aws-dynamodb"; 4 | import * as lambda from "aws-cdk-lib/aws-lambda"; 5 | import * as logs from "aws-cdk-lib/aws-logs"; 6 | import * as sfn from "aws-cdk-lib/aws-stepfunctions"; 7 | import * as tasks from "aws-cdk-lib/aws-stepfunctions-tasks"; 8 | 9 | 10 | /** 11 | * Environment as specified by the lambda.Function environment 12 | */ 13 | class environment { 14 | [key: string]: string; 15 | } 16 | 17 | 18 | /** 19 | * Interface for the bank function environment. 20 | * It contains all the necessary environment variables for the bank functionality. 21 | */ 22 | interface BankFunctionEnvironment extends environment { 23 | BANK_ID: string; 24 | BASE_RATE: string; 25 | MAX_LOAN_AMOUNT: string; 26 | MIN_CREDIT_SCORE: string; 27 | } 28 | 29 | 30 | /** 31 | * CDK Stack implementation of the Loan broker recipient list, 32 | * see https://www.enterpriseintegrationpatterns.com/ramblings/loanbroker_stepfunctions_recipient_list.html 33 | */ 34 | export class LoanBrokerRecipientListStack extends Stack { 35 | constructor(scope: Construct, id: string, props?: StackProps) { 36 | super(scope, id, props); 37 | 38 | 39 | // Set up credit bureau lambda 40 | const creditBureauLambda = new lambda.Function(this, "CreditBureauLambda", { 41 | runtime: lambda.Runtime.NODEJS_18_X, 42 | handler: "app.handler", 43 | code: lambda.Code.fromAsset("credit-bureau"), 44 | functionName: "CreditBureauLambda", 45 | }); 46 | 47 | // Setup get credit score from credit bureau task 48 | const getCreditScoreFromCreditBureau = new tasks.LambdaInvoke(this, "Get Credit Score from credit bureau", { 49 | lambdaFunction: creditBureauLambda, 50 | payload: sfn.TaskInput.fromObject({ 51 | "SSN.$": "$.SSN", 52 | "RequestId.$": "$$.Execution.Id", 53 | }), 54 | resultPath: "$.Credit", 55 | resultSelector: { 56 | "Score.$": "$.Payload.body.score", 57 | "History.$": "$.Payload.body.history", 58 | }, 59 | retryOnServiceExceptions: false, // This is just for development purposes 60 | }); 61 | 62 | // Setup loan broker bank table 63 | const loanBrokerBankTable = new dynamodb.Table(this, "LoanBrokerBanksTable", { 64 | partitionKey: { name: "Type", type: dynamodb.AttributeType.STRING }, 65 | billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, 66 | tableName: "LoanBrokerBanksTable", 67 | 68 | removalPolicy: RemovalPolicy.DESTROY, // This is just for development purposes 69 | }); 70 | 71 | // Setup fetch bank addresses from database task 72 | const fetchBankAddressesFromDatabase = new tasks.DynamoGetItem(this, "Fetch Bank Addresses from database", { 73 | table: loanBrokerBankTable, 74 | key: { Type: tasks.DynamoAttributeValue.fromString("Home") }, 75 | resultPath: "$.Banks", 76 | resultSelector: { 77 | "BankAddress.$": "$.Item.BankAddress.L[*].S", 78 | }, 79 | }); 80 | 81 | // Get individual bank quotes custom state (get function name at runtime from state input is currently not natively supported by the CDK) 82 | const getIndividualBankQuotes = new sfn.CustomState(this, "Get individual bank quotes", { 83 | stateJson: { 84 | Type: "Task", 85 | Resource: "arn:aws:states:::lambda:invoke", 86 | Parameters: { 87 | "FunctionName.$": "$.function", 88 | Payload: { 89 | "SSN.$": "$.SSN", 90 | "Amount.$": "$.Amount", 91 | "Term.$": "$.Term", 92 | "Credit.$": "$.Credit", 93 | }, 94 | }, 95 | ResultSelector: { 96 | "Quote.$": "$.Payload", 97 | }, 98 | }, 99 | }); 100 | 101 | // Get all bank quotes, this will iterator over all banks 102 | const getAllBankQuotes = new sfn.Map(this, "Get all bank quotes", { 103 | itemsPath: "$.Banks.BankAddress", 104 | parameters: { 105 | "function.$": "$$.Map.Item.Value", 106 | "SSN.$": "$.SSN", 107 | "Amount.$": "$.Amount", 108 | "Term.$": "$.Term", 109 | "Credit.$": "$.Credit", 110 | }, 111 | resultPath: "$.Quotes", 112 | }); 113 | 114 | const loanBrokerDefinition = 115 | getCreditScoreFromCreditBureau 116 | .next(fetchBankAddressesFromDatabase) 117 | .next(getAllBankQuotes 118 | .iterator(getIndividualBankQuotes)); 119 | 120 | const loanBrokerLogGroup = new logs.LogGroup(this, "LoanBrokerLogGroup"); 121 | 122 | const loanBroker = new sfn.StateMachine(this, "LoanBroker", { 123 | definitionBody: sfn.DefinitionBody.fromChainable(loanBrokerDefinition), 124 | 125 | stateMachineType: sfn.StateMachineType.STANDARD, 126 | timeout: Duration.minutes(5), 127 | logs: { 128 | destination: loanBrokerLogGroup, 129 | level: sfn.LogLevel.ALL, 130 | includeExecutionData: true, 131 | }, 132 | tracingEnabled: true, 133 | }); 134 | 135 | // Set up the different banks 136 | const bankRecipientPawnshop = this._createBankFunction("BankRecipientPawnshop", { 137 | BANK_ID: "PawnShop", 138 | BASE_RATE: "5", 139 | MAX_LOAN_AMOUNT: "500000", 140 | MIN_CREDIT_SCORE: "400", 141 | }); 142 | 143 | const bankRecipientUniversal = this._createBankFunction("BankRecipientUniversal", { 144 | BANK_ID: "Universal", 145 | BASE_RATE: "4", 146 | MAX_LOAN_AMOUNT: "700000", 147 | MIN_CREDIT_SCORE: "500", 148 | }); 149 | 150 | const bankRecipientPremium = this._createBankFunction("BankRecipientPremium", { 151 | BANK_ID: "Premium", 152 | BASE_RATE: "3", 153 | MAX_LOAN_AMOUNT: "900000", 154 | MIN_CREDIT_SCORE: "600", 155 | }); 156 | 157 | [bankRecipientPawnshop, bankRecipientPremium, bankRecipientUniversal].forEach((bank) => 158 | bank.grantInvoke(loanBroker) 159 | ); 160 | 161 | new CfnOutput(this, "LoanBrokerArn", { 162 | value: loanBroker.stateMachineArn, 163 | }); 164 | } 165 | 166 | 167 | /** 168 | * Creates a bank lambda function. 169 | * 170 | * @param name Name of the bank 171 | * @param env The environment configurations of the bank 172 | * @returns A bank Lambda function 173 | */ 174 | private _createBankFunction(name: string, env: BankFunctionEnvironment) { 175 | return new lambda.Function(this, name, { 176 | runtime: lambda.Runtime.NODEJS_18_X, 177 | handler: "app.handler", 178 | code: lambda.Code.fromAsset("bank"), 179 | functionName: name, 180 | environment: env, 181 | }); 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /cdk/aws-cdk-loan-broker-app.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import "source-map-support/register"; 3 | import * as cdk from "aws-cdk-lib"; 4 | import { LoanBrokerRecipientListStack } from "./LoanBroker-RecipientList-stack"; 5 | import { LoanBrokerPubSubStack } from "./LoanBroker-PubSub-stack"; 6 | 7 | const app = new cdk.App(); 8 | 9 | const loanBrokerRecipientListStack = new LoanBrokerRecipientListStack(app, "LoanBroker-RecipientList-Stack", { 10 | env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION }, 11 | }); 12 | cdk.Tags.of(loanBrokerRecipientListStack).add("Project", "AWS CDK Loan Broker"); 13 | cdk.Tags.of(loanBrokerRecipientListStack).add("Stackname", "LoanBroker-RecipientList-Stack"); 14 | 15 | 16 | const loanBrokerPubSubStack = new LoanBrokerPubSubStack(app, "LoanBroker-PubSub-Stack", { 17 | env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION }, 18 | }); 19 | cdk.Tags.of(loanBrokerPubSubStack).add("Project", "AWS CDK Loan Broker"); 20 | cdk.Tags.of(loanBrokerPubSubStack).add("Stackname", "LoanBroker-PubSub-Stack"); 21 | -------------------------------------------------------------------------------- /cdk/integration-patterns.ts: -------------------------------------------------------------------------------- 1 | import { Construct } from "constructs"; 2 | import { IQueue } from "aws-cdk-lib/aws-sqs"; 3 | import { EventBus, Rule, RuleTargetInput, EventPattern } from "aws-cdk-lib/aws-events"; 4 | import * as targets from "aws-cdk-lib/aws-events-targets"; 5 | 6 | export interface ContentFilterProps { 7 | readonly jsonPath: string; 8 | } 9 | 10 | export class ContentFilter extends Construct { 11 | public readonly ruleTargetInput: RuleTargetInput; 12 | 13 | constructor(scope: Construct, id: string, props: ContentFilterProps) { 14 | super(scope, id); 15 | 16 | this.ruleTargetInput = RuleTargetInput.fromEventPath(props.jsonPath); 17 | } 18 | 19 | static createPayloadFilter(scope: Construct, id: string): ContentFilter { 20 | return new ContentFilter(scope, id, { 21 | jsonPath: "$.detail.responsePayload", 22 | }); 23 | } 24 | } 25 | 26 | export interface MessageFilterProps extends EventPattern {} 27 | 28 | export class MessageFilter extends Construct { 29 | public readonly eventPattern: EventPattern; 30 | 31 | constructor(scope: Construct, id: string, props: MessageFilterProps) { 32 | super(scope, id); 33 | 34 | this.eventPattern = props; 35 | } 36 | 37 | static fieldExists(scope: Construct, id: string, fieldToCheck: string): MessageFilter { 38 | return new MessageFilter(scope, id, { 39 | detail: { 40 | responsePayload: { [fieldToCheck]: [{ exists: true }] }, 41 | }, 42 | }); 43 | } 44 | } 45 | 46 | export interface MessageContentFilterProps { 47 | sourceEventBus: EventBus; 48 | targetQueue: IQueue; 49 | messageFilter: MessageFilter; 50 | contentFilter: ContentFilter; 51 | } 52 | 53 | export class MessageContentFilter extends Construct { 54 | constructor(scope: Construct, id: string, props: MessageContentFilterProps) { 55 | super(scope, id); 56 | 57 | const messageFilterRule = new Rule(scope, id + "Rule", { 58 | eventBus: props.sourceEventBus, 59 | ruleName: id + "Rule", 60 | eventPattern: props.messageFilter.eventPattern, 61 | }); 62 | 63 | var queueMessageProps = props.contentFilter.ruleTargetInput 64 | ? { 65 | message: props.contentFilter.ruleTargetInput, 66 | } 67 | : {}; 68 | messageFilterRule.addTarget(new targets.SqsQueue(props.targetQueue, queueMessageProps)); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /credit-bureau/app.js: -------------------------------------------------------------------------------- 1 | const getRandomInt = (min, max) => { 2 | return min + Math.floor(Math.random() * (max - min)); 3 | }; 4 | 5 | exports.handler = async (event) => { 6 | const min_score = 300; 7 | const max_score = 900; 8 | 9 | var ssn_regex = new RegExp("^\\d{3}-\\d{2}-\\d{4}$"); 10 | if (ssn_regex.test(event.SSN)) { 11 | return { 12 | statusCode: 200, 13 | request_id: event.RequestId, 14 | body: { 15 | SSN: event.SSN, 16 | score: getRandomInt(min_score, max_score), 17 | history: getRandomInt(1, 30), 18 | }, 19 | }; 20 | } else { 21 | return { 22 | statusCode: 400, 23 | request_id: event.RequestId, 24 | body: { 25 | SSN: event.SSN, 26 | }, 27 | }; 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aws-cdk-loan-broker", 3 | "version": "0.1.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "aws-cdk-loan-broker", 9 | "version": "0.1.0", 10 | "license": "Apache-2.0", 11 | "dependencies": { 12 | "aws-cdk-lib": "2.173.2", 13 | "constructs": "^10.4.2", 14 | "source-map-support": "^0.5.21" 15 | }, 16 | "devDependencies": { 17 | "@aws-sdk/client-dynamodb": "^3.714.0", 18 | "@aws-sdk/client-sfn": "^3.714.0", 19 | "@aws-sdk/util-dynamodb": "^3.714.0", 20 | "@types/node": "22.10.2", 21 | "aws-cdk": "2.173.2", 22 | "ts-node": "^10.9.2", 23 | "typescript": "~5.7.2" 24 | } 25 | }, 26 | "node_modules/@aws-cdk/asset-awscli-v1": { 27 | "version": "2.2.215", 28 | "resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.215.tgz", 29 | "integrity": "sha512-D+Jzwpl+zlBGjJf7nuRcz6JFNwqDQ+IzwIq0VSC4LMRRvrkhGE/ZE+zab3EnjmVkipcQqtQe+PVKefgmxETbvA==", 30 | "license": "Apache-2.0" 31 | }, 32 | "node_modules/@aws-cdk/asset-kubectl-v20": { 33 | "version": "2.1.3", 34 | "resolved": "https://registry.npmjs.org/@aws-cdk/asset-kubectl-v20/-/asset-kubectl-v20-2.1.3.tgz", 35 | "integrity": "sha512-cDG1w3ieM6eOT9mTefRuTypk95+oyD7P5X/wRltwmYxU7nZc3+076YEVS6vrjDKr3ADYbfn0lDKpfB1FBtO9CQ==", 36 | "license": "Apache-2.0" 37 | }, 38 | "node_modules/@aws-cdk/asset-node-proxy-agent-v6": { 39 | "version": "2.1.0", 40 | "resolved": "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v6/-/asset-node-proxy-agent-v6-2.1.0.tgz", 41 | "integrity": "sha512-7bY3J8GCVxLupn/kNmpPc5VJz8grx+4RKfnnJiO1LG+uxkZfANZG3RMHhE+qQxxwkyQ9/MfPtTpf748UhR425A==", 42 | "license": "Apache-2.0" 43 | }, 44 | "node_modules/@aws-cdk/cloud-assembly-schema": { 45 | "version": "38.0.1", 46 | "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-38.0.1.tgz", 47 | "integrity": "sha512-KvPe+NMWAulfNVwY7jenFhzhuLhLqJ/OPy5jx7wUstbjnYnjRVLpUHPU3yCjXFE0J8cuJVdx95BJ4rOs66Pi9w==", 48 | "bundleDependencies": [ 49 | "jsonschema", 50 | "semver" 51 | ], 52 | "license": "Apache-2.0", 53 | "dependencies": { 54 | "jsonschema": "^1.4.1", 55 | "semver": "^7.6.3" 56 | } 57 | }, 58 | "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/jsonschema": { 59 | "version": "1.4.1", 60 | "inBundle": true, 61 | "license": "MIT", 62 | "engines": { 63 | "node": "*" 64 | } 65 | }, 66 | "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/semver": { 67 | "version": "7.6.3", 68 | "inBundle": true, 69 | "license": "ISC", 70 | "bin": { 71 | "semver": "bin/semver.js" 72 | }, 73 | "engines": { 74 | "node": ">=10" 75 | } 76 | }, 77 | "node_modules/@aws-crypto/sha256-browser": { 78 | "version": "5.2.0", 79 | "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", 80 | "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", 81 | "dev": true, 82 | "license": "Apache-2.0", 83 | "dependencies": { 84 | "@aws-crypto/sha256-js": "^5.2.0", 85 | "@aws-crypto/supports-web-crypto": "^5.2.0", 86 | "@aws-crypto/util": "^5.2.0", 87 | "@aws-sdk/types": "^3.222.0", 88 | "@aws-sdk/util-locate-window": "^3.0.0", 89 | "@smithy/util-utf8": "^2.0.0", 90 | "tslib": "^2.6.2" 91 | } 92 | }, 93 | "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { 94 | "version": "2.2.0", 95 | "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", 96 | "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", 97 | "dev": true, 98 | "license": "Apache-2.0", 99 | "dependencies": { 100 | "tslib": "^2.6.2" 101 | }, 102 | "engines": { 103 | "node": ">=14.0.0" 104 | } 105 | }, 106 | "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { 107 | "version": "2.2.0", 108 | "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", 109 | "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", 110 | "dev": true, 111 | "license": "Apache-2.0", 112 | "dependencies": { 113 | "@smithy/is-array-buffer": "^2.2.0", 114 | "tslib": "^2.6.2" 115 | }, 116 | "engines": { 117 | "node": ">=14.0.0" 118 | } 119 | }, 120 | "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { 121 | "version": "2.3.0", 122 | "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", 123 | "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", 124 | "dev": true, 125 | "license": "Apache-2.0", 126 | "dependencies": { 127 | "@smithy/util-buffer-from": "^2.2.0", 128 | "tslib": "^2.6.2" 129 | }, 130 | "engines": { 131 | "node": ">=14.0.0" 132 | } 133 | }, 134 | "node_modules/@aws-crypto/sha256-js": { 135 | "version": "5.2.0", 136 | "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", 137 | "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", 138 | "dev": true, 139 | "license": "Apache-2.0", 140 | "dependencies": { 141 | "@aws-crypto/util": "^5.2.0", 142 | "@aws-sdk/types": "^3.222.0", 143 | "tslib": "^2.6.2" 144 | }, 145 | "engines": { 146 | "node": ">=16.0.0" 147 | } 148 | }, 149 | "node_modules/@aws-crypto/supports-web-crypto": { 150 | "version": "5.2.0", 151 | "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", 152 | "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", 153 | "dev": true, 154 | "license": "Apache-2.0", 155 | "dependencies": { 156 | "tslib": "^2.6.2" 157 | } 158 | }, 159 | "node_modules/@aws-crypto/util": { 160 | "version": "5.2.0", 161 | "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", 162 | "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", 163 | "dev": true, 164 | "license": "Apache-2.0", 165 | "dependencies": { 166 | "@aws-sdk/types": "^3.222.0", 167 | "@smithy/util-utf8": "^2.0.0", 168 | "tslib": "^2.6.2" 169 | } 170 | }, 171 | "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { 172 | "version": "2.2.0", 173 | "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", 174 | "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", 175 | "dev": true, 176 | "license": "Apache-2.0", 177 | "dependencies": { 178 | "tslib": "^2.6.2" 179 | }, 180 | "engines": { 181 | "node": ">=14.0.0" 182 | } 183 | }, 184 | "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { 185 | "version": "2.2.0", 186 | "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", 187 | "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", 188 | "dev": true, 189 | "license": "Apache-2.0", 190 | "dependencies": { 191 | "@smithy/is-array-buffer": "^2.2.0", 192 | "tslib": "^2.6.2" 193 | }, 194 | "engines": { 195 | "node": ">=14.0.0" 196 | } 197 | }, 198 | "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { 199 | "version": "2.3.0", 200 | "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", 201 | "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", 202 | "dev": true, 203 | "license": "Apache-2.0", 204 | "dependencies": { 205 | "@smithy/util-buffer-from": "^2.2.0", 206 | "tslib": "^2.6.2" 207 | }, 208 | "engines": { 209 | "node": ">=14.0.0" 210 | } 211 | }, 212 | "node_modules/@aws-sdk/client-dynamodb": { 213 | "version": "3.714.0", 214 | "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.714.0.tgz", 215 | "integrity": "sha512-LM0Gslo3MSRTjvwn30SWJt64dau4hHQcNTXgtaI0LORwha5BnRwRZHsZGwDEHwzmOu31uZZsDHF4rcygl17kSA==", 216 | "dev": true, 217 | "license": "Apache-2.0", 218 | "dependencies": { 219 | "@aws-crypto/sha256-browser": "5.2.0", 220 | "@aws-crypto/sha256-js": "5.2.0", 221 | "@aws-sdk/client-sso-oidc": "3.714.0", 222 | "@aws-sdk/client-sts": "3.714.0", 223 | "@aws-sdk/core": "3.714.0", 224 | "@aws-sdk/credential-provider-node": "3.714.0", 225 | "@aws-sdk/middleware-endpoint-discovery": "3.714.0", 226 | "@aws-sdk/middleware-host-header": "3.714.0", 227 | "@aws-sdk/middleware-logger": "3.714.0", 228 | "@aws-sdk/middleware-recursion-detection": "3.714.0", 229 | "@aws-sdk/middleware-user-agent": "3.714.0", 230 | "@aws-sdk/region-config-resolver": "3.714.0", 231 | "@aws-sdk/types": "3.714.0", 232 | "@aws-sdk/util-endpoints": "3.714.0", 233 | "@aws-sdk/util-user-agent-browser": "3.714.0", 234 | "@aws-sdk/util-user-agent-node": "3.714.0", 235 | "@smithy/config-resolver": "^3.0.13", 236 | "@smithy/core": "^2.5.5", 237 | "@smithy/fetch-http-handler": "^4.1.2", 238 | "@smithy/hash-node": "^3.0.11", 239 | "@smithy/invalid-dependency": "^3.0.11", 240 | "@smithy/middleware-content-length": "^3.0.13", 241 | "@smithy/middleware-endpoint": "^3.2.5", 242 | "@smithy/middleware-retry": "^3.0.30", 243 | "@smithy/middleware-serde": "^3.0.11", 244 | "@smithy/middleware-stack": "^3.0.11", 245 | "@smithy/node-config-provider": "^3.1.12", 246 | "@smithy/node-http-handler": "^3.3.2", 247 | "@smithy/protocol-http": "^4.1.8", 248 | "@smithy/smithy-client": "^3.5.0", 249 | "@smithy/types": "^3.7.2", 250 | "@smithy/url-parser": "^3.0.11", 251 | "@smithy/util-base64": "^3.0.0", 252 | "@smithy/util-body-length-browser": "^3.0.0", 253 | "@smithy/util-body-length-node": "^3.0.0", 254 | "@smithy/util-defaults-mode-browser": "^3.0.30", 255 | "@smithy/util-defaults-mode-node": "^3.0.30", 256 | "@smithy/util-endpoints": "^2.1.7", 257 | "@smithy/util-middleware": "^3.0.11", 258 | "@smithy/util-retry": "^3.0.11", 259 | "@smithy/util-utf8": "^3.0.0", 260 | "@smithy/util-waiter": "^3.2.0", 261 | "@types/uuid": "^9.0.1", 262 | "tslib": "^2.6.2", 263 | "uuid": "^9.0.1" 264 | }, 265 | "engines": { 266 | "node": ">=16.0.0" 267 | } 268 | }, 269 | "node_modules/@aws-sdk/client-sfn": { 270 | "version": "3.714.0", 271 | "resolved": "https://registry.npmjs.org/@aws-sdk/client-sfn/-/client-sfn-3.714.0.tgz", 272 | "integrity": "sha512-qZgFW4QPI/Xtov5DudpS7J19grwytqGpclTc5/jKhvCuC4YcHaL4mWcPyjxJNpsVKrodoIyfEVTikwro6PexUw==", 273 | "dev": true, 274 | "license": "Apache-2.0", 275 | "dependencies": { 276 | "@aws-crypto/sha256-browser": "5.2.0", 277 | "@aws-crypto/sha256-js": "5.2.0", 278 | "@aws-sdk/client-sso-oidc": "3.714.0", 279 | "@aws-sdk/client-sts": "3.714.0", 280 | "@aws-sdk/core": "3.714.0", 281 | "@aws-sdk/credential-provider-node": "3.714.0", 282 | "@aws-sdk/middleware-host-header": "3.714.0", 283 | "@aws-sdk/middleware-logger": "3.714.0", 284 | "@aws-sdk/middleware-recursion-detection": "3.714.0", 285 | "@aws-sdk/middleware-user-agent": "3.714.0", 286 | "@aws-sdk/region-config-resolver": "3.714.0", 287 | "@aws-sdk/types": "3.714.0", 288 | "@aws-sdk/util-endpoints": "3.714.0", 289 | "@aws-sdk/util-user-agent-browser": "3.714.0", 290 | "@aws-sdk/util-user-agent-node": "3.714.0", 291 | "@smithy/config-resolver": "^3.0.13", 292 | "@smithy/core": "^2.5.5", 293 | "@smithy/fetch-http-handler": "^4.1.2", 294 | "@smithy/hash-node": "^3.0.11", 295 | "@smithy/invalid-dependency": "^3.0.11", 296 | "@smithy/middleware-content-length": "^3.0.13", 297 | "@smithy/middleware-endpoint": "^3.2.5", 298 | "@smithy/middleware-retry": "^3.0.30", 299 | "@smithy/middleware-serde": "^3.0.11", 300 | "@smithy/middleware-stack": "^3.0.11", 301 | "@smithy/node-config-provider": "^3.1.12", 302 | "@smithy/node-http-handler": "^3.3.2", 303 | "@smithy/protocol-http": "^4.1.8", 304 | "@smithy/smithy-client": "^3.5.0", 305 | "@smithy/types": "^3.7.2", 306 | "@smithy/url-parser": "^3.0.11", 307 | "@smithy/util-base64": "^3.0.0", 308 | "@smithy/util-body-length-browser": "^3.0.0", 309 | "@smithy/util-body-length-node": "^3.0.0", 310 | "@smithy/util-defaults-mode-browser": "^3.0.30", 311 | "@smithy/util-defaults-mode-node": "^3.0.30", 312 | "@smithy/util-endpoints": "^2.1.7", 313 | "@smithy/util-middleware": "^3.0.11", 314 | "@smithy/util-retry": "^3.0.11", 315 | "@smithy/util-utf8": "^3.0.0", 316 | "@types/uuid": "^9.0.1", 317 | "tslib": "^2.6.2", 318 | "uuid": "^9.0.1" 319 | }, 320 | "engines": { 321 | "node": ">=16.0.0" 322 | } 323 | }, 324 | "node_modules/@aws-sdk/client-sso": { 325 | "version": "3.714.0", 326 | "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.714.0.tgz", 327 | "integrity": "sha512-pFtjY5Ga91qrryo0UfbjetdT2p9rOgtHofogAeEuGjxx7/rupBpdlW0WDOtD/7jhmbhM8WZEr6aH7GLzzkKfCA==", 328 | "dev": true, 329 | "license": "Apache-2.0", 330 | "dependencies": { 331 | "@aws-crypto/sha256-browser": "5.2.0", 332 | "@aws-crypto/sha256-js": "5.2.0", 333 | "@aws-sdk/core": "3.714.0", 334 | "@aws-sdk/middleware-host-header": "3.714.0", 335 | "@aws-sdk/middleware-logger": "3.714.0", 336 | "@aws-sdk/middleware-recursion-detection": "3.714.0", 337 | "@aws-sdk/middleware-user-agent": "3.714.0", 338 | "@aws-sdk/region-config-resolver": "3.714.0", 339 | "@aws-sdk/types": "3.714.0", 340 | "@aws-sdk/util-endpoints": "3.714.0", 341 | "@aws-sdk/util-user-agent-browser": "3.714.0", 342 | "@aws-sdk/util-user-agent-node": "3.714.0", 343 | "@smithy/config-resolver": "^3.0.13", 344 | "@smithy/core": "^2.5.5", 345 | "@smithy/fetch-http-handler": "^4.1.2", 346 | "@smithy/hash-node": "^3.0.11", 347 | "@smithy/invalid-dependency": "^3.0.11", 348 | "@smithy/middleware-content-length": "^3.0.13", 349 | "@smithy/middleware-endpoint": "^3.2.5", 350 | "@smithy/middleware-retry": "^3.0.30", 351 | "@smithy/middleware-serde": "^3.0.11", 352 | "@smithy/middleware-stack": "^3.0.11", 353 | "@smithy/node-config-provider": "^3.1.12", 354 | "@smithy/node-http-handler": "^3.3.2", 355 | "@smithy/protocol-http": "^4.1.8", 356 | "@smithy/smithy-client": "^3.5.0", 357 | "@smithy/types": "^3.7.2", 358 | "@smithy/url-parser": "^3.0.11", 359 | "@smithy/util-base64": "^3.0.0", 360 | "@smithy/util-body-length-browser": "^3.0.0", 361 | "@smithy/util-body-length-node": "^3.0.0", 362 | "@smithy/util-defaults-mode-browser": "^3.0.30", 363 | "@smithy/util-defaults-mode-node": "^3.0.30", 364 | "@smithy/util-endpoints": "^2.1.7", 365 | "@smithy/util-middleware": "^3.0.11", 366 | "@smithy/util-retry": "^3.0.11", 367 | "@smithy/util-utf8": "^3.0.0", 368 | "tslib": "^2.6.2" 369 | }, 370 | "engines": { 371 | "node": ">=16.0.0" 372 | } 373 | }, 374 | "node_modules/@aws-sdk/client-sso-oidc": { 375 | "version": "3.714.0", 376 | "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.714.0.tgz", 377 | "integrity": "sha512-dMvpPUaL3v01psPY1ZyCzQ/w2tOgQTH1if0zBF5r2q7Vc0oOPzbBZgNAhG1bDWlRCBW0iXmoqRFoWUwQ5rtx+A==", 378 | "dev": true, 379 | "license": "Apache-2.0", 380 | "dependencies": { 381 | "@aws-crypto/sha256-browser": "5.2.0", 382 | "@aws-crypto/sha256-js": "5.2.0", 383 | "@aws-sdk/core": "3.714.0", 384 | "@aws-sdk/credential-provider-node": "3.714.0", 385 | "@aws-sdk/middleware-host-header": "3.714.0", 386 | "@aws-sdk/middleware-logger": "3.714.0", 387 | "@aws-sdk/middleware-recursion-detection": "3.714.0", 388 | "@aws-sdk/middleware-user-agent": "3.714.0", 389 | "@aws-sdk/region-config-resolver": "3.714.0", 390 | "@aws-sdk/types": "3.714.0", 391 | "@aws-sdk/util-endpoints": "3.714.0", 392 | "@aws-sdk/util-user-agent-browser": "3.714.0", 393 | "@aws-sdk/util-user-agent-node": "3.714.0", 394 | "@smithy/config-resolver": "^3.0.13", 395 | "@smithy/core": "^2.5.5", 396 | "@smithy/fetch-http-handler": "^4.1.2", 397 | "@smithy/hash-node": "^3.0.11", 398 | "@smithy/invalid-dependency": "^3.0.11", 399 | "@smithy/middleware-content-length": "^3.0.13", 400 | "@smithy/middleware-endpoint": "^3.2.5", 401 | "@smithy/middleware-retry": "^3.0.30", 402 | "@smithy/middleware-serde": "^3.0.11", 403 | "@smithy/middleware-stack": "^3.0.11", 404 | "@smithy/node-config-provider": "^3.1.12", 405 | "@smithy/node-http-handler": "^3.3.2", 406 | "@smithy/protocol-http": "^4.1.8", 407 | "@smithy/smithy-client": "^3.5.0", 408 | "@smithy/types": "^3.7.2", 409 | "@smithy/url-parser": "^3.0.11", 410 | "@smithy/util-base64": "^3.0.0", 411 | "@smithy/util-body-length-browser": "^3.0.0", 412 | "@smithy/util-body-length-node": "^3.0.0", 413 | "@smithy/util-defaults-mode-browser": "^3.0.30", 414 | "@smithy/util-defaults-mode-node": "^3.0.30", 415 | "@smithy/util-endpoints": "^2.1.7", 416 | "@smithy/util-middleware": "^3.0.11", 417 | "@smithy/util-retry": "^3.0.11", 418 | "@smithy/util-utf8": "^3.0.0", 419 | "tslib": "^2.6.2" 420 | }, 421 | "engines": { 422 | "node": ">=16.0.0" 423 | }, 424 | "peerDependencies": { 425 | "@aws-sdk/client-sts": "^3.714.0" 426 | } 427 | }, 428 | "node_modules/@aws-sdk/client-sts": { 429 | "version": "3.714.0", 430 | "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.714.0.tgz", 431 | "integrity": "sha512-ThcXgolapPsOzeavJF4Am312umFyoFBBeiTYD8PQGIiYkbJi4hXcjoWacmtkq6moMmMZSP9iK/ellls7vwY2JQ==", 432 | "dev": true, 433 | "license": "Apache-2.0", 434 | "dependencies": { 435 | "@aws-crypto/sha256-browser": "5.2.0", 436 | "@aws-crypto/sha256-js": "5.2.0", 437 | "@aws-sdk/client-sso-oidc": "3.714.0", 438 | "@aws-sdk/core": "3.714.0", 439 | "@aws-sdk/credential-provider-node": "3.714.0", 440 | "@aws-sdk/middleware-host-header": "3.714.0", 441 | "@aws-sdk/middleware-logger": "3.714.0", 442 | "@aws-sdk/middleware-recursion-detection": "3.714.0", 443 | "@aws-sdk/middleware-user-agent": "3.714.0", 444 | "@aws-sdk/region-config-resolver": "3.714.0", 445 | "@aws-sdk/types": "3.714.0", 446 | "@aws-sdk/util-endpoints": "3.714.0", 447 | "@aws-sdk/util-user-agent-browser": "3.714.0", 448 | "@aws-sdk/util-user-agent-node": "3.714.0", 449 | "@smithy/config-resolver": "^3.0.13", 450 | "@smithy/core": "^2.5.5", 451 | "@smithy/fetch-http-handler": "^4.1.2", 452 | "@smithy/hash-node": "^3.0.11", 453 | "@smithy/invalid-dependency": "^3.0.11", 454 | "@smithy/middleware-content-length": "^3.0.13", 455 | "@smithy/middleware-endpoint": "^3.2.5", 456 | "@smithy/middleware-retry": "^3.0.30", 457 | "@smithy/middleware-serde": "^3.0.11", 458 | "@smithy/middleware-stack": "^3.0.11", 459 | "@smithy/node-config-provider": "^3.1.12", 460 | "@smithy/node-http-handler": "^3.3.2", 461 | "@smithy/protocol-http": "^4.1.8", 462 | "@smithy/smithy-client": "^3.5.0", 463 | "@smithy/types": "^3.7.2", 464 | "@smithy/url-parser": "^3.0.11", 465 | "@smithy/util-base64": "^3.0.0", 466 | "@smithy/util-body-length-browser": "^3.0.0", 467 | "@smithy/util-body-length-node": "^3.0.0", 468 | "@smithy/util-defaults-mode-browser": "^3.0.30", 469 | "@smithy/util-defaults-mode-node": "^3.0.30", 470 | "@smithy/util-endpoints": "^2.1.7", 471 | "@smithy/util-middleware": "^3.0.11", 472 | "@smithy/util-retry": "^3.0.11", 473 | "@smithy/util-utf8": "^3.0.0", 474 | "tslib": "^2.6.2" 475 | }, 476 | "engines": { 477 | "node": ">=16.0.0" 478 | } 479 | }, 480 | "node_modules/@aws-sdk/core": { 481 | "version": "3.714.0", 482 | "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.714.0.tgz", 483 | "integrity": "sha512-TlZ50d8MEPVp9O03SvisOmcmxjxhMDKHJJcrBgYjgDej6QmNfiFwtCRkReXDdkEeXP29ehMs7uPXtmVvPqziYw==", 484 | "dev": true, 485 | "license": "Apache-2.0", 486 | "dependencies": { 487 | "@aws-sdk/types": "3.714.0", 488 | "@smithy/core": "^2.5.5", 489 | "@smithy/node-config-provider": "^3.1.12", 490 | "@smithy/property-provider": "^3.1.11", 491 | "@smithy/protocol-http": "^4.1.8", 492 | "@smithy/signature-v4": "^4.2.4", 493 | "@smithy/smithy-client": "^3.5.0", 494 | "@smithy/types": "^3.7.2", 495 | "@smithy/util-middleware": "^3.0.11", 496 | "fast-xml-parser": "4.4.1", 497 | "tslib": "^2.6.2" 498 | }, 499 | "engines": { 500 | "node": ">=16.0.0" 501 | } 502 | }, 503 | "node_modules/@aws-sdk/credential-provider-env": { 504 | "version": "3.714.0", 505 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.714.0.tgz", 506 | "integrity": "sha512-0S4nKE1a+EHXAInXUeuWkyzVnXzmwIbwLStVidAIoyl6sJF8xGdw+r3AaoTr7p0YXzdoDUsn3wBTCA6ZwgXVbA==", 507 | "dev": true, 508 | "license": "Apache-2.0", 509 | "dependencies": { 510 | "@aws-sdk/core": "3.714.0", 511 | "@aws-sdk/types": "3.714.0", 512 | "@smithy/property-provider": "^3.1.11", 513 | "@smithy/types": "^3.7.2", 514 | "tslib": "^2.6.2" 515 | }, 516 | "engines": { 517 | "node": ">=16.0.0" 518 | } 519 | }, 520 | "node_modules/@aws-sdk/credential-provider-http": { 521 | "version": "3.714.0", 522 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.714.0.tgz", 523 | "integrity": "sha512-1AXEfUSQUQg+x/DpH1XJhjf2yEgTHHatM3cvYu7FZMhRXF28Q5OJDbEFPfdqrK+vmCiYRWhszDb+zuUIvz46bw==", 524 | "dev": true, 525 | "license": "Apache-2.0", 526 | "dependencies": { 527 | "@aws-sdk/core": "3.714.0", 528 | "@aws-sdk/types": "3.714.0", 529 | "@smithy/fetch-http-handler": "^4.1.2", 530 | "@smithy/node-http-handler": "^3.3.2", 531 | "@smithy/property-provider": "^3.1.11", 532 | "@smithy/protocol-http": "^4.1.8", 533 | "@smithy/smithy-client": "^3.5.0", 534 | "@smithy/types": "^3.7.2", 535 | "@smithy/util-stream": "^3.3.2", 536 | "tslib": "^2.6.2" 537 | }, 538 | "engines": { 539 | "node": ">=16.0.0" 540 | } 541 | }, 542 | "node_modules/@aws-sdk/credential-provider-ini": { 543 | "version": "3.714.0", 544 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.714.0.tgz", 545 | "integrity": "sha512-w5wOcgBngfcvVev5wnYWXoc/W2ewVmGJkfRdGquhFt8pkUxktyd8eXehqkP7u31SONVlgy96EFTdSCzWpTrqOw==", 546 | "dev": true, 547 | "license": "Apache-2.0", 548 | "dependencies": { 549 | "@aws-sdk/core": "3.714.0", 550 | "@aws-sdk/credential-provider-env": "3.714.0", 551 | "@aws-sdk/credential-provider-http": "3.714.0", 552 | "@aws-sdk/credential-provider-process": "3.714.0", 553 | "@aws-sdk/credential-provider-sso": "3.714.0", 554 | "@aws-sdk/credential-provider-web-identity": "3.714.0", 555 | "@aws-sdk/types": "3.714.0", 556 | "@smithy/credential-provider-imds": "^3.2.8", 557 | "@smithy/property-provider": "^3.1.11", 558 | "@smithy/shared-ini-file-loader": "^3.1.12", 559 | "@smithy/types": "^3.7.2", 560 | "tslib": "^2.6.2" 561 | }, 562 | "engines": { 563 | "node": ">=16.0.0" 564 | }, 565 | "peerDependencies": { 566 | "@aws-sdk/client-sts": "^3.714.0" 567 | } 568 | }, 569 | "node_modules/@aws-sdk/credential-provider-node": { 570 | "version": "3.714.0", 571 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.714.0.tgz", 572 | "integrity": "sha512-ebho1HYNKzaw0ZfbI9kEicSW8J7tsOoV6EJajsjfFnuP+GY9J5Oi4759GEq1Qqj7GxIhrySOZFzif/hxAXPWtQ==", 573 | "dev": true, 574 | "license": "Apache-2.0", 575 | "dependencies": { 576 | "@aws-sdk/credential-provider-env": "3.714.0", 577 | "@aws-sdk/credential-provider-http": "3.714.0", 578 | "@aws-sdk/credential-provider-ini": "3.714.0", 579 | "@aws-sdk/credential-provider-process": "3.714.0", 580 | "@aws-sdk/credential-provider-sso": "3.714.0", 581 | "@aws-sdk/credential-provider-web-identity": "3.714.0", 582 | "@aws-sdk/types": "3.714.0", 583 | "@smithy/credential-provider-imds": "^3.2.8", 584 | "@smithy/property-provider": "^3.1.11", 585 | "@smithy/shared-ini-file-loader": "^3.1.12", 586 | "@smithy/types": "^3.7.2", 587 | "tslib": "^2.6.2" 588 | }, 589 | "engines": { 590 | "node": ">=16.0.0" 591 | } 592 | }, 593 | "node_modules/@aws-sdk/credential-provider-process": { 594 | "version": "3.714.0", 595 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.714.0.tgz", 596 | "integrity": "sha512-mHM+zYJDUiXggBx4YvQgMOhbkV07KUib8/jWPnAZbUJcRncN/yevAp/WNocjUN4VaBWkooJUgoTET/okRK+TCQ==", 597 | "dev": true, 598 | "license": "Apache-2.0", 599 | "dependencies": { 600 | "@aws-sdk/core": "3.714.0", 601 | "@aws-sdk/types": "3.714.0", 602 | "@smithy/property-provider": "^3.1.11", 603 | "@smithy/shared-ini-file-loader": "^3.1.12", 604 | "@smithy/types": "^3.7.2", 605 | "tslib": "^2.6.2" 606 | }, 607 | "engines": { 608 | "node": ">=16.0.0" 609 | } 610 | }, 611 | "node_modules/@aws-sdk/credential-provider-sso": { 612 | "version": "3.714.0", 613 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.714.0.tgz", 614 | "integrity": "sha512-LQyHUQd+/A0PO96m6/A3KeekRplRpG9AmwLn8VPknlmACAhhbWHehzerCTd42V8dClf5pigr25/aVqh/2p/sRw==", 615 | "dev": true, 616 | "license": "Apache-2.0", 617 | "dependencies": { 618 | "@aws-sdk/client-sso": "3.714.0", 619 | "@aws-sdk/core": "3.714.0", 620 | "@aws-sdk/token-providers": "3.714.0", 621 | "@aws-sdk/types": "3.714.0", 622 | "@smithy/property-provider": "^3.1.11", 623 | "@smithy/shared-ini-file-loader": "^3.1.12", 624 | "@smithy/types": "^3.7.2", 625 | "tslib": "^2.6.2" 626 | }, 627 | "engines": { 628 | "node": ">=16.0.0" 629 | } 630 | }, 631 | "node_modules/@aws-sdk/credential-provider-web-identity": { 632 | "version": "3.714.0", 633 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.714.0.tgz", 634 | "integrity": "sha512-piKfEJvLrGZ0bH4NPO19d1dtfCZi2p6YJUK/9vRCD1rvJidOuHNeUwIcxTnkIMovQHX12rZVvU9ub0C3CwegUQ==", 635 | "dev": true, 636 | "license": "Apache-2.0", 637 | "dependencies": { 638 | "@aws-sdk/core": "3.714.0", 639 | "@aws-sdk/types": "3.714.0", 640 | "@smithy/property-provider": "^3.1.11", 641 | "@smithy/types": "^3.7.2", 642 | "tslib": "^2.6.2" 643 | }, 644 | "engines": { 645 | "node": ">=16.0.0" 646 | }, 647 | "peerDependencies": { 648 | "@aws-sdk/client-sts": "^3.714.0" 649 | } 650 | }, 651 | "node_modules/@aws-sdk/endpoint-cache": { 652 | "version": "3.693.0", 653 | "resolved": "https://registry.npmjs.org/@aws-sdk/endpoint-cache/-/endpoint-cache-3.693.0.tgz", 654 | "integrity": "sha512-/zK0ZZncBf5FbTfo8rJMcQIXXk4Ibhe5zEMiwFNivVPR2uNC0+oqfwXz7vjxwY0t6BPE3Bs4h9uFEz4xuGCY6w==", 655 | "dev": true, 656 | "license": "Apache-2.0", 657 | "dependencies": { 658 | "mnemonist": "0.38.3", 659 | "tslib": "^2.6.2" 660 | }, 661 | "engines": { 662 | "node": ">=16.0.0" 663 | } 664 | }, 665 | "node_modules/@aws-sdk/middleware-endpoint-discovery": { 666 | "version": "3.714.0", 667 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.714.0.tgz", 668 | "integrity": "sha512-WttOa+M6/aPCK0OHPlWPBaQDTVhfKsWYnmDNvS2d0qvoJEjZuGRyf5DxcA2gWt3MMekxwq9IxOpdA5R9T70HiA==", 669 | "dev": true, 670 | "license": "Apache-2.0", 671 | "dependencies": { 672 | "@aws-sdk/endpoint-cache": "3.693.0", 673 | "@aws-sdk/types": "3.714.0", 674 | "@smithy/node-config-provider": "^3.1.12", 675 | "@smithy/protocol-http": "^4.1.8", 676 | "@smithy/types": "^3.7.2", 677 | "tslib": "^2.6.2" 678 | }, 679 | "engines": { 680 | "node": ">=16.0.0" 681 | } 682 | }, 683 | "node_modules/@aws-sdk/middleware-host-header": { 684 | "version": "3.714.0", 685 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.714.0.tgz", 686 | "integrity": "sha512-6l68kjNrh5QC8FGX3I3geBDavWN5Tg1RLHJ2HLA8ByGBtJyCwnz3hEkKfaxn0bBx0hF9DzbfjEOUF6cDqy2Kjg==", 687 | "dev": true, 688 | "license": "Apache-2.0", 689 | "dependencies": { 690 | "@aws-sdk/types": "3.714.0", 691 | "@smithy/protocol-http": "^4.1.8", 692 | "@smithy/types": "^3.7.2", 693 | "tslib": "^2.6.2" 694 | }, 695 | "engines": { 696 | "node": ">=16.0.0" 697 | } 698 | }, 699 | "node_modules/@aws-sdk/middleware-logger": { 700 | "version": "3.714.0", 701 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.714.0.tgz", 702 | "integrity": "sha512-RkqHlMvQWUaRklU1bMfUuBvdWwxgUtEqpADaHXlGVj3vtEY2UgBjy+57CveC4MByqKIunNvVHBBbjrGVtwY7Lg==", 703 | "dev": true, 704 | "license": "Apache-2.0", 705 | "dependencies": { 706 | "@aws-sdk/types": "3.714.0", 707 | "@smithy/types": "^3.7.2", 708 | "tslib": "^2.6.2" 709 | }, 710 | "engines": { 711 | "node": ">=16.0.0" 712 | } 713 | }, 714 | "node_modules/@aws-sdk/middleware-recursion-detection": { 715 | "version": "3.714.0", 716 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.714.0.tgz", 717 | "integrity": "sha512-AVU5ixnh93nqtsfgNc284oXsXaadyHGPHpql/jwgaaqQfEXjS/1/j3j9E/vpacfTTz2Vzo7hAOjnvrOXSEVDaA==", 718 | "dev": true, 719 | "license": "Apache-2.0", 720 | "dependencies": { 721 | "@aws-sdk/types": "3.714.0", 722 | "@smithy/protocol-http": "^4.1.8", 723 | "@smithy/types": "^3.7.2", 724 | "tslib": "^2.6.2" 725 | }, 726 | "engines": { 727 | "node": ">=16.0.0" 728 | } 729 | }, 730 | "node_modules/@aws-sdk/middleware-user-agent": { 731 | "version": "3.714.0", 732 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.714.0.tgz", 733 | "integrity": "sha512-OgLjJf7WxUqA2OgiqGCfIc68gsbXlIG8LjObBiF0qlMStAd0L23AGuK5VmYinJlsle9qUpwQvWgKFKaDgdQXgA==", 734 | "dev": true, 735 | "license": "Apache-2.0", 736 | "dependencies": { 737 | "@aws-sdk/core": "3.714.0", 738 | "@aws-sdk/types": "3.714.0", 739 | "@aws-sdk/util-endpoints": "3.714.0", 740 | "@smithy/core": "^2.5.5", 741 | "@smithy/protocol-http": "^4.1.8", 742 | "@smithy/types": "^3.7.2", 743 | "tslib": "^2.6.2" 744 | }, 745 | "engines": { 746 | "node": ">=16.0.0" 747 | } 748 | }, 749 | "node_modules/@aws-sdk/region-config-resolver": { 750 | "version": "3.714.0", 751 | "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.714.0.tgz", 752 | "integrity": "sha512-HJzsQxgMOAzZrbf/YIqEx30or4tZK1oNAk6Wm6xecUQx+23JXIaePRu1YFUOLBBERQ4QBPpISFurZWBMZ5ibAw==", 753 | "dev": true, 754 | "license": "Apache-2.0", 755 | "dependencies": { 756 | "@aws-sdk/types": "3.714.0", 757 | "@smithy/node-config-provider": "^3.1.12", 758 | "@smithy/types": "^3.7.2", 759 | "@smithy/util-config-provider": "^3.0.0", 760 | "@smithy/util-middleware": "^3.0.11", 761 | "tslib": "^2.6.2" 762 | }, 763 | "engines": { 764 | "node": ">=16.0.0" 765 | } 766 | }, 767 | "node_modules/@aws-sdk/token-providers": { 768 | "version": "3.714.0", 769 | "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.714.0.tgz", 770 | "integrity": "sha512-vKN064aLE3kl+Zl16Ony3jltHnMddMBT7JRkP1L+lLywhA0PcAKxpdvComul/sTBWnbnwLnaS5NsDUhcWySH8A==", 771 | "dev": true, 772 | "license": "Apache-2.0", 773 | "dependencies": { 774 | "@aws-sdk/types": "3.714.0", 775 | "@smithy/property-provider": "^3.1.11", 776 | "@smithy/shared-ini-file-loader": "^3.1.12", 777 | "@smithy/types": "^3.7.2", 778 | "tslib": "^2.6.2" 779 | }, 780 | "engines": { 781 | "node": ">=16.0.0" 782 | }, 783 | "peerDependencies": { 784 | "@aws-sdk/client-sso-oidc": "^3.714.0" 785 | } 786 | }, 787 | "node_modules/@aws-sdk/types": { 788 | "version": "3.714.0", 789 | "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.714.0.tgz", 790 | "integrity": "sha512-ZjpP2gYbSFlxxaUDa1Il5AVvfggvUPbjzzB/l3q0gIE5Thd6xKW+yzEpt2mLZ5s5UaYSABZbF94g8NUOF4CVGA==", 791 | "dev": true, 792 | "license": "Apache-2.0", 793 | "dependencies": { 794 | "@smithy/types": "^3.7.2", 795 | "tslib": "^2.6.2" 796 | }, 797 | "engines": { 798 | "node": ">=16.0.0" 799 | } 800 | }, 801 | "node_modules/@aws-sdk/util-dynamodb": { 802 | "version": "3.714.0", 803 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.714.0.tgz", 804 | "integrity": "sha512-R2hD9d4YCpC2d8aZA8+r6HxGK9Av5WgB5R8kXZaufvQXyWzGmvtKm6xxU4QUHm6X24c9G6lISh2aRvOzPNFRow==", 805 | "dev": true, 806 | "license": "Apache-2.0", 807 | "dependencies": { 808 | "tslib": "^2.6.2" 809 | }, 810 | "engines": { 811 | "node": ">=16.0.0" 812 | }, 813 | "peerDependencies": { 814 | "@aws-sdk/client-dynamodb": "^3.714.0" 815 | } 816 | }, 817 | "node_modules/@aws-sdk/util-endpoints": { 818 | "version": "3.714.0", 819 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.714.0.tgz", 820 | "integrity": "sha512-Xv+Z2lhe7w7ZZRsgBwBMZgGTVmS+dkkj2S13uNHAx9lhB5ovM8PhK5G/j28xYf6vIibeuHkRAbb7/ozdZIGR+A==", 821 | "dev": true, 822 | "license": "Apache-2.0", 823 | "dependencies": { 824 | "@aws-sdk/types": "3.714.0", 825 | "@smithy/types": "^3.7.2", 826 | "@smithy/util-endpoints": "^2.1.7", 827 | "tslib": "^2.6.2" 828 | }, 829 | "engines": { 830 | "node": ">=16.0.0" 831 | } 832 | }, 833 | "node_modules/@aws-sdk/util-locate-window": { 834 | "version": "3.693.0", 835 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.693.0.tgz", 836 | "integrity": "sha512-ttrag6haJLWABhLqtg1Uf+4LgHWIMOVSYL+VYZmAp2v4PUGOwWmWQH0Zk8RM7YuQcLfH/EoR72/Yxz6A4FKcuw==", 837 | "dev": true, 838 | "license": "Apache-2.0", 839 | "dependencies": { 840 | "tslib": "^2.6.2" 841 | }, 842 | "engines": { 843 | "node": ">=16.0.0" 844 | } 845 | }, 846 | "node_modules/@aws-sdk/util-user-agent-browser": { 847 | "version": "3.714.0", 848 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.714.0.tgz", 849 | "integrity": "sha512-OdJJ03cP9/MgIVToPJPCPUImbpZzTcwdIgbXC0tUQPJhbD7b7cB4LdnkhNHko+MptpOrCq4CPY/33EpOjRdofw==", 850 | "dev": true, 851 | "license": "Apache-2.0", 852 | "dependencies": { 853 | "@aws-sdk/types": "3.714.0", 854 | "@smithy/types": "^3.7.2", 855 | "bowser": "^2.11.0", 856 | "tslib": "^2.6.2" 857 | } 858 | }, 859 | "node_modules/@aws-sdk/util-user-agent-node": { 860 | "version": "3.714.0", 861 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.714.0.tgz", 862 | "integrity": "sha512-x8JoZb7yBEbNUmHUNoRAP4L++6A5uZCVf2yFLw8CZKpH4q+Cf1a68ou48OfnND3H0rbBnLXc/3uOlseRvd57/g==", 863 | "dev": true, 864 | "license": "Apache-2.0", 865 | "dependencies": { 866 | "@aws-sdk/middleware-user-agent": "3.714.0", 867 | "@aws-sdk/types": "3.714.0", 868 | "@smithy/node-config-provider": "^3.1.12", 869 | "@smithy/types": "^3.7.2", 870 | "tslib": "^2.6.2" 871 | }, 872 | "engines": { 873 | "node": ">=16.0.0" 874 | }, 875 | "peerDependencies": { 876 | "aws-crt": ">=1.0.0" 877 | }, 878 | "peerDependenciesMeta": { 879 | "aws-crt": { 880 | "optional": true 881 | } 882 | } 883 | }, 884 | "node_modules/@cspotcode/source-map-support": { 885 | "version": "0.8.1", 886 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", 887 | "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", 888 | "dev": true, 889 | "license": "MIT", 890 | "dependencies": { 891 | "@jridgewell/trace-mapping": "0.3.9" 892 | }, 893 | "engines": { 894 | "node": ">=12" 895 | } 896 | }, 897 | "node_modules/@jridgewell/resolve-uri": { 898 | "version": "3.1.2", 899 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", 900 | "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", 901 | "dev": true, 902 | "license": "MIT", 903 | "engines": { 904 | "node": ">=6.0.0" 905 | } 906 | }, 907 | "node_modules/@jridgewell/sourcemap-codec": { 908 | "version": "1.5.0", 909 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", 910 | "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", 911 | "dev": true, 912 | "license": "MIT" 913 | }, 914 | "node_modules/@jridgewell/trace-mapping": { 915 | "version": "0.3.9", 916 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", 917 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", 918 | "dev": true, 919 | "license": "MIT", 920 | "dependencies": { 921 | "@jridgewell/resolve-uri": "^3.0.3", 922 | "@jridgewell/sourcemap-codec": "^1.4.10" 923 | } 924 | }, 925 | "node_modules/@smithy/abort-controller": { 926 | "version": "3.1.9", 927 | "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.9.tgz", 928 | "integrity": "sha512-yiW0WI30zj8ZKoSYNx90no7ugVn3khlyH/z5W8qtKBtVE6awRALbhSG+2SAHA1r6bO/6M9utxYKVZ3PCJ1rWxw==", 929 | "dev": true, 930 | "license": "Apache-2.0", 931 | "dependencies": { 932 | "@smithy/types": "^3.7.2", 933 | "tslib": "^2.6.2" 934 | }, 935 | "engines": { 936 | "node": ">=16.0.0" 937 | } 938 | }, 939 | "node_modules/@smithy/config-resolver": { 940 | "version": "3.0.13", 941 | "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.13.tgz", 942 | "integrity": "sha512-Gr/qwzyPaTL1tZcq8WQyHhTZREER5R1Wytmz4WnVGL4onA3dNk6Btll55c8Vr58pLdvWZmtG8oZxJTw3t3q7Jg==", 943 | "dev": true, 944 | "license": "Apache-2.0", 945 | "dependencies": { 946 | "@smithy/node-config-provider": "^3.1.12", 947 | "@smithy/types": "^3.7.2", 948 | "@smithy/util-config-provider": "^3.0.0", 949 | "@smithy/util-middleware": "^3.0.11", 950 | "tslib": "^2.6.2" 951 | }, 952 | "engines": { 953 | "node": ">=16.0.0" 954 | } 955 | }, 956 | "node_modules/@smithy/core": { 957 | "version": "2.5.5", 958 | "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.5.5.tgz", 959 | "integrity": "sha512-G8G/sDDhXA7o0bOvkc7bgai6POuSld/+XhNnWAbpQTpLv2OZPvyqQ58tLPPlz0bSNsXktldDDREIv1LczFeNEw==", 960 | "dev": true, 961 | "license": "Apache-2.0", 962 | "dependencies": { 963 | "@smithy/middleware-serde": "^3.0.11", 964 | "@smithy/protocol-http": "^4.1.8", 965 | "@smithy/types": "^3.7.2", 966 | "@smithy/util-body-length-browser": "^3.0.0", 967 | "@smithy/util-middleware": "^3.0.11", 968 | "@smithy/util-stream": "^3.3.2", 969 | "@smithy/util-utf8": "^3.0.0", 970 | "tslib": "^2.6.2" 971 | }, 972 | "engines": { 973 | "node": ">=16.0.0" 974 | } 975 | }, 976 | "node_modules/@smithy/credential-provider-imds": { 977 | "version": "3.2.8", 978 | "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.8.tgz", 979 | "integrity": "sha512-ZCY2yD0BY+K9iMXkkbnjo+08T2h8/34oHd0Jmh6BZUSZwaaGlGCyBT/3wnS7u7Xl33/EEfN4B6nQr3Gx5bYxgw==", 980 | "dev": true, 981 | "license": "Apache-2.0", 982 | "dependencies": { 983 | "@smithy/node-config-provider": "^3.1.12", 984 | "@smithy/property-provider": "^3.1.11", 985 | "@smithy/types": "^3.7.2", 986 | "@smithy/url-parser": "^3.0.11", 987 | "tslib": "^2.6.2" 988 | }, 989 | "engines": { 990 | "node": ">=16.0.0" 991 | } 992 | }, 993 | "node_modules/@smithy/fetch-http-handler": { 994 | "version": "4.1.2", 995 | "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-4.1.2.tgz", 996 | "integrity": "sha512-R7rU7Ae3ItU4rC0c5mB2sP5mJNbCfoDc8I5XlYjIZnquyUwec7fEo78F6DA3SmgJgkU1qTMcZJuGblxZsl10ZA==", 997 | "dev": true, 998 | "license": "Apache-2.0", 999 | "dependencies": { 1000 | "@smithy/protocol-http": "^4.1.8", 1001 | "@smithy/querystring-builder": "^3.0.11", 1002 | "@smithy/types": "^3.7.2", 1003 | "@smithy/util-base64": "^3.0.0", 1004 | "tslib": "^2.6.2" 1005 | } 1006 | }, 1007 | "node_modules/@smithy/hash-node": { 1008 | "version": "3.0.11", 1009 | "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.11.tgz", 1010 | "integrity": "sha512-emP23rwYyZhQBvklqTtwetkQlqbNYirDiEEwXl2v0GYWMnCzxst7ZaRAnWuy28njp5kAH54lvkdG37MblZzaHA==", 1011 | "dev": true, 1012 | "license": "Apache-2.0", 1013 | "dependencies": { 1014 | "@smithy/types": "^3.7.2", 1015 | "@smithy/util-buffer-from": "^3.0.0", 1016 | "@smithy/util-utf8": "^3.0.0", 1017 | "tslib": "^2.6.2" 1018 | }, 1019 | "engines": { 1020 | "node": ">=16.0.0" 1021 | } 1022 | }, 1023 | "node_modules/@smithy/invalid-dependency": { 1024 | "version": "3.0.11", 1025 | "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.11.tgz", 1026 | "integrity": "sha512-NuQmVPEJjUX6c+UELyVz8kUx8Q539EDeNwbRyu4IIF8MeV7hUtq1FB3SHVyki2u++5XLMFqngeMKk7ccspnNyQ==", 1027 | "dev": true, 1028 | "license": "Apache-2.0", 1029 | "dependencies": { 1030 | "@smithy/types": "^3.7.2", 1031 | "tslib": "^2.6.2" 1032 | } 1033 | }, 1034 | "node_modules/@smithy/is-array-buffer": { 1035 | "version": "3.0.0", 1036 | "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", 1037 | "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", 1038 | "dev": true, 1039 | "license": "Apache-2.0", 1040 | "dependencies": { 1041 | "tslib": "^2.6.2" 1042 | }, 1043 | "engines": { 1044 | "node": ">=16.0.0" 1045 | } 1046 | }, 1047 | "node_modules/@smithy/middleware-content-length": { 1048 | "version": "3.0.13", 1049 | "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.13.tgz", 1050 | "integrity": "sha512-zfMhzojhFpIX3P5ug7jxTjfUcIPcGjcQYzB9t+rv0g1TX7B0QdwONW+ATouaLoD7h7LOw/ZlXfkq4xJ/g2TrIw==", 1051 | "dev": true, 1052 | "license": "Apache-2.0", 1053 | "dependencies": { 1054 | "@smithy/protocol-http": "^4.1.8", 1055 | "@smithy/types": "^3.7.2", 1056 | "tslib": "^2.6.2" 1057 | }, 1058 | "engines": { 1059 | "node": ">=16.0.0" 1060 | } 1061 | }, 1062 | "node_modules/@smithy/middleware-endpoint": { 1063 | "version": "3.2.5", 1064 | "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.2.5.tgz", 1065 | "integrity": "sha512-VhJNs/s/lyx4weiZdXSloBgoLoS8osV0dKIain8nGmx7of3QFKu5BSdEuk1z/U8x9iwes1i+XCiNusEvuK1ijg==", 1066 | "dev": true, 1067 | "license": "Apache-2.0", 1068 | "dependencies": { 1069 | "@smithy/core": "^2.5.5", 1070 | "@smithy/middleware-serde": "^3.0.11", 1071 | "@smithy/node-config-provider": "^3.1.12", 1072 | "@smithy/shared-ini-file-loader": "^3.1.12", 1073 | "@smithy/types": "^3.7.2", 1074 | "@smithy/url-parser": "^3.0.11", 1075 | "@smithy/util-middleware": "^3.0.11", 1076 | "tslib": "^2.6.2" 1077 | }, 1078 | "engines": { 1079 | "node": ">=16.0.0" 1080 | } 1081 | }, 1082 | "node_modules/@smithy/middleware-retry": { 1083 | "version": "3.0.30", 1084 | "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.30.tgz", 1085 | "integrity": "sha512-6323RL2BvAR3VQpTjHpa52kH/iSHyxd/G9ohb2MkBk2Ucu+oMtRXT8yi7KTSIS9nb58aupG6nO0OlXnQOAcvmQ==", 1086 | "dev": true, 1087 | "license": "Apache-2.0", 1088 | "dependencies": { 1089 | "@smithy/node-config-provider": "^3.1.12", 1090 | "@smithy/protocol-http": "^4.1.8", 1091 | "@smithy/service-error-classification": "^3.0.11", 1092 | "@smithy/smithy-client": "^3.5.0", 1093 | "@smithy/types": "^3.7.2", 1094 | "@smithy/util-middleware": "^3.0.11", 1095 | "@smithy/util-retry": "^3.0.11", 1096 | "tslib": "^2.6.2", 1097 | "uuid": "^9.0.1" 1098 | }, 1099 | "engines": { 1100 | "node": ">=16.0.0" 1101 | } 1102 | }, 1103 | "node_modules/@smithy/middleware-serde": { 1104 | "version": "3.0.11", 1105 | "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.11.tgz", 1106 | "integrity": "sha512-KzPAeySp/fOoQA82TpnwItvX8BBURecpx6ZMu75EZDkAcnPtO6vf7q4aH5QHs/F1s3/snQaSFbbUMcFFZ086Mw==", 1107 | "dev": true, 1108 | "license": "Apache-2.0", 1109 | "dependencies": { 1110 | "@smithy/types": "^3.7.2", 1111 | "tslib": "^2.6.2" 1112 | }, 1113 | "engines": { 1114 | "node": ">=16.0.0" 1115 | } 1116 | }, 1117 | "node_modules/@smithy/middleware-stack": { 1118 | "version": "3.0.11", 1119 | "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.11.tgz", 1120 | "integrity": "sha512-1HGo9a6/ikgOMrTrWL/WiN9N8GSVYpuRQO5kjstAq4CvV59bjqnh7TbdXGQ4vxLD3xlSjfBjq5t1SOELePsLnA==", 1121 | "dev": true, 1122 | "license": "Apache-2.0", 1123 | "dependencies": { 1124 | "@smithy/types": "^3.7.2", 1125 | "tslib": "^2.6.2" 1126 | }, 1127 | "engines": { 1128 | "node": ">=16.0.0" 1129 | } 1130 | }, 1131 | "node_modules/@smithy/node-config-provider": { 1132 | "version": "3.1.12", 1133 | "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.12.tgz", 1134 | "integrity": "sha512-O9LVEu5J/u/FuNlZs+L7Ikn3lz7VB9hb0GtPT9MQeiBmtK8RSY3ULmsZgXhe6VAlgTw0YO+paQx4p8xdbs43vQ==", 1135 | "dev": true, 1136 | "license": "Apache-2.0", 1137 | "dependencies": { 1138 | "@smithy/property-provider": "^3.1.11", 1139 | "@smithy/shared-ini-file-loader": "^3.1.12", 1140 | "@smithy/types": "^3.7.2", 1141 | "tslib": "^2.6.2" 1142 | }, 1143 | "engines": { 1144 | "node": ">=16.0.0" 1145 | } 1146 | }, 1147 | "node_modules/@smithy/node-http-handler": { 1148 | "version": "3.3.2", 1149 | "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.3.2.tgz", 1150 | "integrity": "sha512-t4ng1DAd527vlxvOfKFYEe6/QFBcsj7WpNlWTyjorwXXcKw3XlltBGbyHfSJ24QT84nF+agDha9tNYpzmSRZPA==", 1151 | "dev": true, 1152 | "license": "Apache-2.0", 1153 | "dependencies": { 1154 | "@smithy/abort-controller": "^3.1.9", 1155 | "@smithy/protocol-http": "^4.1.8", 1156 | "@smithy/querystring-builder": "^3.0.11", 1157 | "@smithy/types": "^3.7.2", 1158 | "tslib": "^2.6.2" 1159 | }, 1160 | "engines": { 1161 | "node": ">=16.0.0" 1162 | } 1163 | }, 1164 | "node_modules/@smithy/property-provider": { 1165 | "version": "3.1.11", 1166 | "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.11.tgz", 1167 | "integrity": "sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A==", 1168 | "dev": true, 1169 | "license": "Apache-2.0", 1170 | "dependencies": { 1171 | "@smithy/types": "^3.7.2", 1172 | "tslib": "^2.6.2" 1173 | }, 1174 | "engines": { 1175 | "node": ">=16.0.0" 1176 | } 1177 | }, 1178 | "node_modules/@smithy/protocol-http": { 1179 | "version": "4.1.8", 1180 | "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.8.tgz", 1181 | "integrity": "sha512-hmgIAVyxw1LySOwkgMIUN0kjN8TG9Nc85LJeEmEE/cNEe2rkHDUWhnJf2gxcSRFLWsyqWsrZGw40ROjUogg+Iw==", 1182 | "dev": true, 1183 | "license": "Apache-2.0", 1184 | "dependencies": { 1185 | "@smithy/types": "^3.7.2", 1186 | "tslib": "^2.6.2" 1187 | }, 1188 | "engines": { 1189 | "node": ">=16.0.0" 1190 | } 1191 | }, 1192 | "node_modules/@smithy/querystring-builder": { 1193 | "version": "3.0.11", 1194 | "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.11.tgz", 1195 | "integrity": "sha512-u+5HV/9uJaeLj5XTb6+IEF/dokWWkEqJ0XiaRRogyREmKGUgZnNecLucADLdauWFKUNbQfulHFEZEdjwEBjXRg==", 1196 | "dev": true, 1197 | "license": "Apache-2.0", 1198 | "dependencies": { 1199 | "@smithy/types": "^3.7.2", 1200 | "@smithy/util-uri-escape": "^3.0.0", 1201 | "tslib": "^2.6.2" 1202 | }, 1203 | "engines": { 1204 | "node": ">=16.0.0" 1205 | } 1206 | }, 1207 | "node_modules/@smithy/querystring-parser": { 1208 | "version": "3.0.11", 1209 | "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.11.tgz", 1210 | "integrity": "sha512-Je3kFvCsFMnso1ilPwA7GtlbPaTixa3WwC+K21kmMZHsBEOZYQaqxcMqeFFoU7/slFjKDIpiiPydvdJm8Q/MCw==", 1211 | "dev": true, 1212 | "license": "Apache-2.0", 1213 | "dependencies": { 1214 | "@smithy/types": "^3.7.2", 1215 | "tslib": "^2.6.2" 1216 | }, 1217 | "engines": { 1218 | "node": ">=16.0.0" 1219 | } 1220 | }, 1221 | "node_modules/@smithy/service-error-classification": { 1222 | "version": "3.0.11", 1223 | "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.11.tgz", 1224 | "integrity": "sha512-QnYDPkyewrJzCyaeI2Rmp7pDwbUETe+hU8ADkXmgNusO1bgHBH7ovXJiYmba8t0fNfJx75fE8dlM6SEmZxheog==", 1225 | "dev": true, 1226 | "license": "Apache-2.0", 1227 | "dependencies": { 1228 | "@smithy/types": "^3.7.2" 1229 | }, 1230 | "engines": { 1231 | "node": ">=16.0.0" 1232 | } 1233 | }, 1234 | "node_modules/@smithy/shared-ini-file-loader": { 1235 | "version": "3.1.12", 1236 | "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.12.tgz", 1237 | "integrity": "sha512-1xKSGI+U9KKdbG2qDvIR9dGrw3CNx+baqJfyr0igKEpjbHL5stsqAesYBzHChYHlelWtb87VnLWlhvfCz13H8Q==", 1238 | "dev": true, 1239 | "license": "Apache-2.0", 1240 | "dependencies": { 1241 | "@smithy/types": "^3.7.2", 1242 | "tslib": "^2.6.2" 1243 | }, 1244 | "engines": { 1245 | "node": ">=16.0.0" 1246 | } 1247 | }, 1248 | "node_modules/@smithy/signature-v4": { 1249 | "version": "4.2.4", 1250 | "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.2.4.tgz", 1251 | "integrity": "sha512-5JWeMQYg81TgU4cG+OexAWdvDTs5JDdbEZx+Qr1iPbvo91QFGzjy0IkXAKaXUHqmKUJgSHK0ZxnCkgZpzkeNTA==", 1252 | "dev": true, 1253 | "license": "Apache-2.0", 1254 | "dependencies": { 1255 | "@smithy/is-array-buffer": "^3.0.0", 1256 | "@smithy/protocol-http": "^4.1.8", 1257 | "@smithy/types": "^3.7.2", 1258 | "@smithy/util-hex-encoding": "^3.0.0", 1259 | "@smithy/util-middleware": "^3.0.11", 1260 | "@smithy/util-uri-escape": "^3.0.0", 1261 | "@smithy/util-utf8": "^3.0.0", 1262 | "tslib": "^2.6.2" 1263 | }, 1264 | "engines": { 1265 | "node": ">=16.0.0" 1266 | } 1267 | }, 1268 | "node_modules/@smithy/smithy-client": { 1269 | "version": "3.5.0", 1270 | "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.5.0.tgz", 1271 | "integrity": "sha512-Y8FeOa7gbDfCWf7njrkoRATPa5eNLUEjlJS5z5rXatYuGkCb80LbHcu8AQR8qgAZZaNHCLyo2N+pxPsV7l+ivg==", 1272 | "dev": true, 1273 | "license": "Apache-2.0", 1274 | "dependencies": { 1275 | "@smithy/core": "^2.5.5", 1276 | "@smithy/middleware-endpoint": "^3.2.5", 1277 | "@smithy/middleware-stack": "^3.0.11", 1278 | "@smithy/protocol-http": "^4.1.8", 1279 | "@smithy/types": "^3.7.2", 1280 | "@smithy/util-stream": "^3.3.2", 1281 | "tslib": "^2.6.2" 1282 | }, 1283 | "engines": { 1284 | "node": ">=16.0.0" 1285 | } 1286 | }, 1287 | "node_modules/@smithy/types": { 1288 | "version": "3.7.2", 1289 | "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.7.2.tgz", 1290 | "integrity": "sha512-bNwBYYmN8Eh9RyjS1p2gW6MIhSO2rl7X9QeLM8iTdcGRP+eDiIWDt66c9IysCc22gefKszZv+ubV9qZc7hdESg==", 1291 | "dev": true, 1292 | "license": "Apache-2.0", 1293 | "dependencies": { 1294 | "tslib": "^2.6.2" 1295 | }, 1296 | "engines": { 1297 | "node": ">=16.0.0" 1298 | } 1299 | }, 1300 | "node_modules/@smithy/url-parser": { 1301 | "version": "3.0.11", 1302 | "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.11.tgz", 1303 | "integrity": "sha512-TmlqXkSk8ZPhfc+SQutjmFr5FjC0av3GZP4B/10caK1SbRwe/v+Wzu/R6xEKxoNqL+8nY18s1byiy6HqPG37Aw==", 1304 | "dev": true, 1305 | "license": "Apache-2.0", 1306 | "dependencies": { 1307 | "@smithy/querystring-parser": "^3.0.11", 1308 | "@smithy/types": "^3.7.2", 1309 | "tslib": "^2.6.2" 1310 | } 1311 | }, 1312 | "node_modules/@smithy/util-base64": { 1313 | "version": "3.0.0", 1314 | "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", 1315 | "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", 1316 | "dev": true, 1317 | "license": "Apache-2.0", 1318 | "dependencies": { 1319 | "@smithy/util-buffer-from": "^3.0.0", 1320 | "@smithy/util-utf8": "^3.0.0", 1321 | "tslib": "^2.6.2" 1322 | }, 1323 | "engines": { 1324 | "node": ">=16.0.0" 1325 | } 1326 | }, 1327 | "node_modules/@smithy/util-body-length-browser": { 1328 | "version": "3.0.0", 1329 | "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", 1330 | "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==", 1331 | "dev": true, 1332 | "license": "Apache-2.0", 1333 | "dependencies": { 1334 | "tslib": "^2.6.2" 1335 | } 1336 | }, 1337 | "node_modules/@smithy/util-body-length-node": { 1338 | "version": "3.0.0", 1339 | "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", 1340 | "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", 1341 | "dev": true, 1342 | "license": "Apache-2.0", 1343 | "dependencies": { 1344 | "tslib": "^2.6.2" 1345 | }, 1346 | "engines": { 1347 | "node": ">=16.0.0" 1348 | } 1349 | }, 1350 | "node_modules/@smithy/util-buffer-from": { 1351 | "version": "3.0.0", 1352 | "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", 1353 | "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", 1354 | "dev": true, 1355 | "license": "Apache-2.0", 1356 | "dependencies": { 1357 | "@smithy/is-array-buffer": "^3.0.0", 1358 | "tslib": "^2.6.2" 1359 | }, 1360 | "engines": { 1361 | "node": ">=16.0.0" 1362 | } 1363 | }, 1364 | "node_modules/@smithy/util-config-provider": { 1365 | "version": "3.0.0", 1366 | "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", 1367 | "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", 1368 | "dev": true, 1369 | "license": "Apache-2.0", 1370 | "dependencies": { 1371 | "tslib": "^2.6.2" 1372 | }, 1373 | "engines": { 1374 | "node": ">=16.0.0" 1375 | } 1376 | }, 1377 | "node_modules/@smithy/util-defaults-mode-browser": { 1378 | "version": "3.0.30", 1379 | "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.30.tgz", 1380 | "integrity": "sha512-nLuGmgfcr0gzm64pqF2UT4SGWVG8UGviAdayDlVzJPNa6Z4lqvpDzdRXmLxtOdEjVlTOEdpZ9dd3ZMMu488mzg==", 1381 | "dev": true, 1382 | "license": "Apache-2.0", 1383 | "dependencies": { 1384 | "@smithy/property-provider": "^3.1.11", 1385 | "@smithy/smithy-client": "^3.5.0", 1386 | "@smithy/types": "^3.7.2", 1387 | "bowser": "^2.11.0", 1388 | "tslib": "^2.6.2" 1389 | }, 1390 | "engines": { 1391 | "node": ">= 10.0.0" 1392 | } 1393 | }, 1394 | "node_modules/@smithy/util-defaults-mode-node": { 1395 | "version": "3.0.30", 1396 | "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.30.tgz", 1397 | "integrity": "sha512-OD63eWoH68vp75mYcfYyuVH+p7Li/mY4sYOROnauDrtObo1cS4uWfsy/zhOTW8F8ZPxQC1ZXZKVxoxvMGUv2Ow==", 1398 | "dev": true, 1399 | "license": "Apache-2.0", 1400 | "dependencies": { 1401 | "@smithy/config-resolver": "^3.0.13", 1402 | "@smithy/credential-provider-imds": "^3.2.8", 1403 | "@smithy/node-config-provider": "^3.1.12", 1404 | "@smithy/property-provider": "^3.1.11", 1405 | "@smithy/smithy-client": "^3.5.0", 1406 | "@smithy/types": "^3.7.2", 1407 | "tslib": "^2.6.2" 1408 | }, 1409 | "engines": { 1410 | "node": ">= 10.0.0" 1411 | } 1412 | }, 1413 | "node_modules/@smithy/util-endpoints": { 1414 | "version": "2.1.7", 1415 | "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.1.7.tgz", 1416 | "integrity": "sha512-tSfcqKcN/Oo2STEYCABVuKgJ76nyyr6skGl9t15hs+YaiU06sgMkN7QYjo0BbVw+KT26zok3IzbdSOksQ4YzVw==", 1417 | "dev": true, 1418 | "license": "Apache-2.0", 1419 | "dependencies": { 1420 | "@smithy/node-config-provider": "^3.1.12", 1421 | "@smithy/types": "^3.7.2", 1422 | "tslib": "^2.6.2" 1423 | }, 1424 | "engines": { 1425 | "node": ">=16.0.0" 1426 | } 1427 | }, 1428 | "node_modules/@smithy/util-hex-encoding": { 1429 | "version": "3.0.0", 1430 | "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", 1431 | "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", 1432 | "dev": true, 1433 | "license": "Apache-2.0", 1434 | "dependencies": { 1435 | "tslib": "^2.6.2" 1436 | }, 1437 | "engines": { 1438 | "node": ">=16.0.0" 1439 | } 1440 | }, 1441 | "node_modules/@smithy/util-middleware": { 1442 | "version": "3.0.11", 1443 | "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.11.tgz", 1444 | "integrity": "sha512-dWpyc1e1R6VoXrwLoLDd57U1z6CwNSdkM69Ie4+6uYh2GC7Vg51Qtan7ITzczuVpqezdDTKJGJB95fFvvjU/ow==", 1445 | "dev": true, 1446 | "license": "Apache-2.0", 1447 | "dependencies": { 1448 | "@smithy/types": "^3.7.2", 1449 | "tslib": "^2.6.2" 1450 | }, 1451 | "engines": { 1452 | "node": ">=16.0.0" 1453 | } 1454 | }, 1455 | "node_modules/@smithy/util-retry": { 1456 | "version": "3.0.11", 1457 | "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.11.tgz", 1458 | "integrity": "sha512-hJUC6W7A3DQgaee3Hp9ZFcOxVDZzmBIRBPlUAk8/fSOEl7pE/aX7Dci0JycNOnm9Mfr0KV2XjIlUOcGWXQUdVQ==", 1459 | "dev": true, 1460 | "license": "Apache-2.0", 1461 | "dependencies": { 1462 | "@smithy/service-error-classification": "^3.0.11", 1463 | "@smithy/types": "^3.7.2", 1464 | "tslib": "^2.6.2" 1465 | }, 1466 | "engines": { 1467 | "node": ">=16.0.0" 1468 | } 1469 | }, 1470 | "node_modules/@smithy/util-stream": { 1471 | "version": "3.3.2", 1472 | "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.3.2.tgz", 1473 | "integrity": "sha512-sInAqdiVeisUGYAv/FrXpmJ0b4WTFmciTRqzhb7wVuem9BHvhIG7tpiYHLDWrl2stOokNZpTTGqz3mzB2qFwXg==", 1474 | "dev": true, 1475 | "license": "Apache-2.0", 1476 | "dependencies": { 1477 | "@smithy/fetch-http-handler": "^4.1.2", 1478 | "@smithy/node-http-handler": "^3.3.2", 1479 | "@smithy/types": "^3.7.2", 1480 | "@smithy/util-base64": "^3.0.0", 1481 | "@smithy/util-buffer-from": "^3.0.0", 1482 | "@smithy/util-hex-encoding": "^3.0.0", 1483 | "@smithy/util-utf8": "^3.0.0", 1484 | "tslib": "^2.6.2" 1485 | }, 1486 | "engines": { 1487 | "node": ">=16.0.0" 1488 | } 1489 | }, 1490 | "node_modules/@smithy/util-uri-escape": { 1491 | "version": "3.0.0", 1492 | "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", 1493 | "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", 1494 | "dev": true, 1495 | "license": "Apache-2.0", 1496 | "dependencies": { 1497 | "tslib": "^2.6.2" 1498 | }, 1499 | "engines": { 1500 | "node": ">=16.0.0" 1501 | } 1502 | }, 1503 | "node_modules/@smithy/util-utf8": { 1504 | "version": "3.0.0", 1505 | "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", 1506 | "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", 1507 | "dev": true, 1508 | "license": "Apache-2.0", 1509 | "dependencies": { 1510 | "@smithy/util-buffer-from": "^3.0.0", 1511 | "tslib": "^2.6.2" 1512 | }, 1513 | "engines": { 1514 | "node": ">=16.0.0" 1515 | } 1516 | }, 1517 | "node_modules/@smithy/util-waiter": { 1518 | "version": "3.2.0", 1519 | "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-3.2.0.tgz", 1520 | "integrity": "sha512-PpjSboaDUE6yl+1qlg3Si57++e84oXdWGbuFUSAciXsVfEZJJJupR2Nb0QuXHiunt2vGR+1PTizOMvnUPaG2Qg==", 1521 | "dev": true, 1522 | "license": "Apache-2.0", 1523 | "dependencies": { 1524 | "@smithy/abort-controller": "^3.1.9", 1525 | "@smithy/types": "^3.7.2", 1526 | "tslib": "^2.6.2" 1527 | }, 1528 | "engines": { 1529 | "node": ">=16.0.0" 1530 | } 1531 | }, 1532 | "node_modules/@tsconfig/node10": { 1533 | "version": "1.0.11", 1534 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", 1535 | "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", 1536 | "dev": true, 1537 | "license": "MIT" 1538 | }, 1539 | "node_modules/@tsconfig/node12": { 1540 | "version": "1.0.11", 1541 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", 1542 | "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", 1543 | "dev": true, 1544 | "license": "MIT" 1545 | }, 1546 | "node_modules/@tsconfig/node14": { 1547 | "version": "1.0.3", 1548 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", 1549 | "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", 1550 | "dev": true, 1551 | "license": "MIT" 1552 | }, 1553 | "node_modules/@tsconfig/node16": { 1554 | "version": "1.0.4", 1555 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", 1556 | "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", 1557 | "dev": true, 1558 | "license": "MIT" 1559 | }, 1560 | "node_modules/@types/node": { 1561 | "version": "22.10.2", 1562 | "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", 1563 | "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", 1564 | "dev": true, 1565 | "license": "MIT", 1566 | "dependencies": { 1567 | "undici-types": "~6.20.0" 1568 | } 1569 | }, 1570 | "node_modules/@types/uuid": { 1571 | "version": "9.0.8", 1572 | "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", 1573 | "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", 1574 | "dev": true, 1575 | "license": "MIT" 1576 | }, 1577 | "node_modules/acorn": { 1578 | "version": "8.14.0", 1579 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", 1580 | "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", 1581 | "dev": true, 1582 | "license": "MIT", 1583 | "bin": { 1584 | "acorn": "bin/acorn" 1585 | }, 1586 | "engines": { 1587 | "node": ">=0.4.0" 1588 | } 1589 | }, 1590 | "node_modules/acorn-walk": { 1591 | "version": "8.3.4", 1592 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", 1593 | "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", 1594 | "dev": true, 1595 | "license": "MIT", 1596 | "dependencies": { 1597 | "acorn": "^8.11.0" 1598 | }, 1599 | "engines": { 1600 | "node": ">=0.4.0" 1601 | } 1602 | }, 1603 | "node_modules/arg": { 1604 | "version": "4.1.3", 1605 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 1606 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 1607 | "dev": true, 1608 | "license": "MIT" 1609 | }, 1610 | "node_modules/aws-cdk": { 1611 | "version": "2.173.2", 1612 | "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.173.2.tgz", 1613 | "integrity": "sha512-qyMU4FoRJdZDUpsOBqyRBALBjf5A2N/MaHKX9iJUkbTET+d+nR07x3ai4TcEES+8pqPFHMTKpQMRDXs9Py/15w==", 1614 | "dev": true, 1615 | "license": "Apache-2.0", 1616 | "bin": { 1617 | "cdk": "bin/cdk" 1618 | }, 1619 | "engines": { 1620 | "node": ">= 14.15.0" 1621 | }, 1622 | "optionalDependencies": { 1623 | "fsevents": "2.3.2" 1624 | } 1625 | }, 1626 | "node_modules/aws-cdk-lib": { 1627 | "version": "2.173.2", 1628 | "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.173.2.tgz", 1629 | "integrity": "sha512-cL9+z8Pl3VZGoO7BwdsrFAOeud/vSl3at7OvmhihbNprMN15XuFUx/rViAU5OI1m92NbV4NBzYSLbSeCwYLNyw==", 1630 | "bundleDependencies": [ 1631 | "@balena/dockerignore", 1632 | "case", 1633 | "fs-extra", 1634 | "ignore", 1635 | "jsonschema", 1636 | "minimatch", 1637 | "punycode", 1638 | "semver", 1639 | "table", 1640 | "yaml", 1641 | "mime-types" 1642 | ], 1643 | "license": "Apache-2.0", 1644 | "dependencies": { 1645 | "@aws-cdk/asset-awscli-v1": "^2.2.208", 1646 | "@aws-cdk/asset-kubectl-v20": "^2.1.3", 1647 | "@aws-cdk/asset-node-proxy-agent-v6": "^2.1.0", 1648 | "@aws-cdk/cloud-assembly-schema": "^38.0.1", 1649 | "@balena/dockerignore": "^1.0.2", 1650 | "case": "1.6.3", 1651 | "fs-extra": "^11.2.0", 1652 | "ignore": "^5.3.2", 1653 | "jsonschema": "^1.4.1", 1654 | "mime-types": "^2.1.35", 1655 | "minimatch": "^3.1.2", 1656 | "punycode": "^2.3.1", 1657 | "semver": "^7.6.3", 1658 | "table": "^6.8.2", 1659 | "yaml": "1.10.2" 1660 | }, 1661 | "engines": { 1662 | "node": ">= 14.15.0" 1663 | }, 1664 | "peerDependencies": { 1665 | "constructs": "^10.0.0" 1666 | } 1667 | }, 1668 | "node_modules/aws-cdk-lib/node_modules/@balena/dockerignore": { 1669 | "version": "1.0.2", 1670 | "inBundle": true, 1671 | "license": "Apache-2.0" 1672 | }, 1673 | "node_modules/aws-cdk-lib/node_modules/ajv": { 1674 | "version": "8.17.1", 1675 | "inBundle": true, 1676 | "license": "MIT", 1677 | "dependencies": { 1678 | "fast-deep-equal": "^3.1.3", 1679 | "fast-uri": "^3.0.1", 1680 | "json-schema-traverse": "^1.0.0", 1681 | "require-from-string": "^2.0.2" 1682 | }, 1683 | "funding": { 1684 | "type": "github", 1685 | "url": "https://github.com/sponsors/epoberezkin" 1686 | } 1687 | }, 1688 | "node_modules/aws-cdk-lib/node_modules/ansi-regex": { 1689 | "version": "5.0.1", 1690 | "inBundle": true, 1691 | "license": "MIT", 1692 | "engines": { 1693 | "node": ">=8" 1694 | } 1695 | }, 1696 | "node_modules/aws-cdk-lib/node_modules/ansi-styles": { 1697 | "version": "4.3.0", 1698 | "inBundle": true, 1699 | "license": "MIT", 1700 | "dependencies": { 1701 | "color-convert": "^2.0.1" 1702 | }, 1703 | "engines": { 1704 | "node": ">=8" 1705 | }, 1706 | "funding": { 1707 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 1708 | } 1709 | }, 1710 | "node_modules/aws-cdk-lib/node_modules/astral-regex": { 1711 | "version": "2.0.0", 1712 | "inBundle": true, 1713 | "license": "MIT", 1714 | "engines": { 1715 | "node": ">=8" 1716 | } 1717 | }, 1718 | "node_modules/aws-cdk-lib/node_modules/balanced-match": { 1719 | "version": "1.0.2", 1720 | "inBundle": true, 1721 | "license": "MIT" 1722 | }, 1723 | "node_modules/aws-cdk-lib/node_modules/brace-expansion": { 1724 | "version": "1.1.11", 1725 | "inBundle": true, 1726 | "license": "MIT", 1727 | "dependencies": { 1728 | "balanced-match": "^1.0.0", 1729 | "concat-map": "0.0.1" 1730 | } 1731 | }, 1732 | "node_modules/aws-cdk-lib/node_modules/case": { 1733 | "version": "1.6.3", 1734 | "inBundle": true, 1735 | "license": "(MIT OR GPL-3.0-or-later)", 1736 | "engines": { 1737 | "node": ">= 0.8.0" 1738 | } 1739 | }, 1740 | "node_modules/aws-cdk-lib/node_modules/color-convert": { 1741 | "version": "2.0.1", 1742 | "inBundle": true, 1743 | "license": "MIT", 1744 | "dependencies": { 1745 | "color-name": "~1.1.4" 1746 | }, 1747 | "engines": { 1748 | "node": ">=7.0.0" 1749 | } 1750 | }, 1751 | "node_modules/aws-cdk-lib/node_modules/color-name": { 1752 | "version": "1.1.4", 1753 | "inBundle": true, 1754 | "license": "MIT" 1755 | }, 1756 | "node_modules/aws-cdk-lib/node_modules/concat-map": { 1757 | "version": "0.0.1", 1758 | "inBundle": true, 1759 | "license": "MIT" 1760 | }, 1761 | "node_modules/aws-cdk-lib/node_modules/emoji-regex": { 1762 | "version": "8.0.0", 1763 | "inBundle": true, 1764 | "license": "MIT" 1765 | }, 1766 | "node_modules/aws-cdk-lib/node_modules/fast-deep-equal": { 1767 | "version": "3.1.3", 1768 | "inBundle": true, 1769 | "license": "MIT" 1770 | }, 1771 | "node_modules/aws-cdk-lib/node_modules/fast-uri": { 1772 | "version": "3.0.3", 1773 | "inBundle": true, 1774 | "license": "BSD-3-Clause" 1775 | }, 1776 | "node_modules/aws-cdk-lib/node_modules/fs-extra": { 1777 | "version": "11.2.0", 1778 | "inBundle": true, 1779 | "license": "MIT", 1780 | "dependencies": { 1781 | "graceful-fs": "^4.2.0", 1782 | "jsonfile": "^6.0.1", 1783 | "universalify": "^2.0.0" 1784 | }, 1785 | "engines": { 1786 | "node": ">=14.14" 1787 | } 1788 | }, 1789 | "node_modules/aws-cdk-lib/node_modules/graceful-fs": { 1790 | "version": "4.2.11", 1791 | "inBundle": true, 1792 | "license": "ISC" 1793 | }, 1794 | "node_modules/aws-cdk-lib/node_modules/ignore": { 1795 | "version": "5.3.2", 1796 | "inBundle": true, 1797 | "license": "MIT", 1798 | "engines": { 1799 | "node": ">= 4" 1800 | } 1801 | }, 1802 | "node_modules/aws-cdk-lib/node_modules/is-fullwidth-code-point": { 1803 | "version": "3.0.0", 1804 | "inBundle": true, 1805 | "license": "MIT", 1806 | "engines": { 1807 | "node": ">=8" 1808 | } 1809 | }, 1810 | "node_modules/aws-cdk-lib/node_modules/json-schema-traverse": { 1811 | "version": "1.0.0", 1812 | "inBundle": true, 1813 | "license": "MIT" 1814 | }, 1815 | "node_modules/aws-cdk-lib/node_modules/jsonfile": { 1816 | "version": "6.1.0", 1817 | "inBundle": true, 1818 | "license": "MIT", 1819 | "dependencies": { 1820 | "universalify": "^2.0.0" 1821 | }, 1822 | "optionalDependencies": { 1823 | "graceful-fs": "^4.1.6" 1824 | } 1825 | }, 1826 | "node_modules/aws-cdk-lib/node_modules/jsonschema": { 1827 | "version": "1.4.1", 1828 | "inBundle": true, 1829 | "license": "MIT", 1830 | "engines": { 1831 | "node": "*" 1832 | } 1833 | }, 1834 | "node_modules/aws-cdk-lib/node_modules/lodash.truncate": { 1835 | "version": "4.4.2", 1836 | "inBundle": true, 1837 | "license": "MIT" 1838 | }, 1839 | "node_modules/aws-cdk-lib/node_modules/mime-db": { 1840 | "version": "1.52.0", 1841 | "inBundle": true, 1842 | "license": "MIT", 1843 | "engines": { 1844 | "node": ">= 0.6" 1845 | } 1846 | }, 1847 | "node_modules/aws-cdk-lib/node_modules/mime-types": { 1848 | "version": "2.1.35", 1849 | "inBundle": true, 1850 | "license": "MIT", 1851 | "dependencies": { 1852 | "mime-db": "1.52.0" 1853 | }, 1854 | "engines": { 1855 | "node": ">= 0.6" 1856 | } 1857 | }, 1858 | "node_modules/aws-cdk-lib/node_modules/minimatch": { 1859 | "version": "3.1.2", 1860 | "inBundle": true, 1861 | "license": "ISC", 1862 | "dependencies": { 1863 | "brace-expansion": "^1.1.7" 1864 | }, 1865 | "engines": { 1866 | "node": "*" 1867 | } 1868 | }, 1869 | "node_modules/aws-cdk-lib/node_modules/punycode": { 1870 | "version": "2.3.1", 1871 | "inBundle": true, 1872 | "license": "MIT", 1873 | "engines": { 1874 | "node": ">=6" 1875 | } 1876 | }, 1877 | "node_modules/aws-cdk-lib/node_modules/require-from-string": { 1878 | "version": "2.0.2", 1879 | "inBundle": true, 1880 | "license": "MIT", 1881 | "engines": { 1882 | "node": ">=0.10.0" 1883 | } 1884 | }, 1885 | "node_modules/aws-cdk-lib/node_modules/semver": { 1886 | "version": "7.6.3", 1887 | "inBundle": true, 1888 | "license": "ISC", 1889 | "bin": { 1890 | "semver": "bin/semver.js" 1891 | }, 1892 | "engines": { 1893 | "node": ">=10" 1894 | } 1895 | }, 1896 | "node_modules/aws-cdk-lib/node_modules/slice-ansi": { 1897 | "version": "4.0.0", 1898 | "inBundle": true, 1899 | "license": "MIT", 1900 | "dependencies": { 1901 | "ansi-styles": "^4.0.0", 1902 | "astral-regex": "^2.0.0", 1903 | "is-fullwidth-code-point": "^3.0.0" 1904 | }, 1905 | "engines": { 1906 | "node": ">=10" 1907 | }, 1908 | "funding": { 1909 | "url": "https://github.com/chalk/slice-ansi?sponsor=1" 1910 | } 1911 | }, 1912 | "node_modules/aws-cdk-lib/node_modules/string-width": { 1913 | "version": "4.2.3", 1914 | "inBundle": true, 1915 | "license": "MIT", 1916 | "dependencies": { 1917 | "emoji-regex": "^8.0.0", 1918 | "is-fullwidth-code-point": "^3.0.0", 1919 | "strip-ansi": "^6.0.1" 1920 | }, 1921 | "engines": { 1922 | "node": ">=8" 1923 | } 1924 | }, 1925 | "node_modules/aws-cdk-lib/node_modules/strip-ansi": { 1926 | "version": "6.0.1", 1927 | "inBundle": true, 1928 | "license": "MIT", 1929 | "dependencies": { 1930 | "ansi-regex": "^5.0.1" 1931 | }, 1932 | "engines": { 1933 | "node": ">=8" 1934 | } 1935 | }, 1936 | "node_modules/aws-cdk-lib/node_modules/table": { 1937 | "version": "6.8.2", 1938 | "inBundle": true, 1939 | "license": "BSD-3-Clause", 1940 | "dependencies": { 1941 | "ajv": "^8.0.1", 1942 | "lodash.truncate": "^4.4.2", 1943 | "slice-ansi": "^4.0.0", 1944 | "string-width": "^4.2.3", 1945 | "strip-ansi": "^6.0.1" 1946 | }, 1947 | "engines": { 1948 | "node": ">=10.0.0" 1949 | } 1950 | }, 1951 | "node_modules/aws-cdk-lib/node_modules/universalify": { 1952 | "version": "2.0.1", 1953 | "inBundle": true, 1954 | "license": "MIT", 1955 | "engines": { 1956 | "node": ">= 10.0.0" 1957 | } 1958 | }, 1959 | "node_modules/aws-cdk-lib/node_modules/yaml": { 1960 | "version": "1.10.2", 1961 | "inBundle": true, 1962 | "license": "ISC", 1963 | "engines": { 1964 | "node": ">= 6" 1965 | } 1966 | }, 1967 | "node_modules/bowser": { 1968 | "version": "2.11.0", 1969 | "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", 1970 | "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", 1971 | "dev": true, 1972 | "license": "MIT" 1973 | }, 1974 | "node_modules/buffer-from": { 1975 | "version": "1.1.2", 1976 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 1977 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", 1978 | "license": "MIT" 1979 | }, 1980 | "node_modules/constructs": { 1981 | "version": "10.4.2", 1982 | "resolved": "https://registry.npmjs.org/constructs/-/constructs-10.4.2.tgz", 1983 | "integrity": "sha512-wsNxBlAott2qg8Zv87q3eYZYgheb9lchtBfjHzzLHtXbttwSrHPs1NNQbBrmbb1YZvYg2+Vh0Dor76w4mFxJkA==", 1984 | "license": "Apache-2.0" 1985 | }, 1986 | "node_modules/create-require": { 1987 | "version": "1.1.1", 1988 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", 1989 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", 1990 | "dev": true, 1991 | "license": "MIT" 1992 | }, 1993 | "node_modules/diff": { 1994 | "version": "4.0.2", 1995 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 1996 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 1997 | "dev": true, 1998 | "license": "BSD-3-Clause", 1999 | "engines": { 2000 | "node": ">=0.3.1" 2001 | } 2002 | }, 2003 | "node_modules/fast-xml-parser": { 2004 | "version": "4.4.1", 2005 | "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", 2006 | "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", 2007 | "dev": true, 2008 | "funding": [ 2009 | { 2010 | "type": "github", 2011 | "url": "https://github.com/sponsors/NaturalIntelligence" 2012 | }, 2013 | { 2014 | "type": "paypal", 2015 | "url": "https://paypal.me/naturalintelligence" 2016 | } 2017 | ], 2018 | "license": "MIT", 2019 | "dependencies": { 2020 | "strnum": "^1.0.5" 2021 | }, 2022 | "bin": { 2023 | "fxparser": "src/cli/cli.js" 2024 | } 2025 | }, 2026 | "node_modules/fsevents": { 2027 | "version": "2.3.2", 2028 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 2029 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 2030 | "dev": true, 2031 | "hasInstallScript": true, 2032 | "license": "MIT", 2033 | "optional": true, 2034 | "os": [ 2035 | "darwin" 2036 | ], 2037 | "engines": { 2038 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 2039 | } 2040 | }, 2041 | "node_modules/make-error": { 2042 | "version": "1.3.6", 2043 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 2044 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 2045 | "dev": true, 2046 | "license": "ISC" 2047 | }, 2048 | "node_modules/mnemonist": { 2049 | "version": "0.38.3", 2050 | "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.3.tgz", 2051 | "integrity": "sha512-2K9QYubXx/NAjv4VLq1d1Ly8pWNC5L3BrixtdkyTegXWJIqY+zLNDhhX/A+ZwWt70tB1S8H4BE8FLYEFyNoOBw==", 2052 | "dev": true, 2053 | "license": "MIT", 2054 | "dependencies": { 2055 | "obliterator": "^1.6.1" 2056 | } 2057 | }, 2058 | "node_modules/obliterator": { 2059 | "version": "1.6.1", 2060 | "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-1.6.1.tgz", 2061 | "integrity": "sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig==", 2062 | "dev": true, 2063 | "license": "MIT" 2064 | }, 2065 | "node_modules/source-map": { 2066 | "version": "0.6.1", 2067 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 2068 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 2069 | "license": "BSD-3-Clause", 2070 | "engines": { 2071 | "node": ">=0.10.0" 2072 | } 2073 | }, 2074 | "node_modules/source-map-support": { 2075 | "version": "0.5.21", 2076 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", 2077 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", 2078 | "license": "MIT", 2079 | "dependencies": { 2080 | "buffer-from": "^1.0.0", 2081 | "source-map": "^0.6.0" 2082 | } 2083 | }, 2084 | "node_modules/strnum": { 2085 | "version": "1.0.5", 2086 | "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", 2087 | "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", 2088 | "dev": true, 2089 | "license": "MIT" 2090 | }, 2091 | "node_modules/ts-node": { 2092 | "version": "10.9.2", 2093 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", 2094 | "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", 2095 | "dev": true, 2096 | "license": "MIT", 2097 | "dependencies": { 2098 | "@cspotcode/source-map-support": "^0.8.0", 2099 | "@tsconfig/node10": "^1.0.7", 2100 | "@tsconfig/node12": "^1.0.7", 2101 | "@tsconfig/node14": "^1.0.0", 2102 | "@tsconfig/node16": "^1.0.2", 2103 | "acorn": "^8.4.1", 2104 | "acorn-walk": "^8.1.1", 2105 | "arg": "^4.1.0", 2106 | "create-require": "^1.1.0", 2107 | "diff": "^4.0.1", 2108 | "make-error": "^1.1.1", 2109 | "v8-compile-cache-lib": "^3.0.1", 2110 | "yn": "3.1.1" 2111 | }, 2112 | "bin": { 2113 | "ts-node": "dist/bin.js", 2114 | "ts-node-cwd": "dist/bin-cwd.js", 2115 | "ts-node-esm": "dist/bin-esm.js", 2116 | "ts-node-script": "dist/bin-script.js", 2117 | "ts-node-transpile-only": "dist/bin-transpile.js", 2118 | "ts-script": "dist/bin-script-deprecated.js" 2119 | }, 2120 | "peerDependencies": { 2121 | "@swc/core": ">=1.2.50", 2122 | "@swc/wasm": ">=1.2.50", 2123 | "@types/node": "*", 2124 | "typescript": ">=2.7" 2125 | }, 2126 | "peerDependenciesMeta": { 2127 | "@swc/core": { 2128 | "optional": true 2129 | }, 2130 | "@swc/wasm": { 2131 | "optional": true 2132 | } 2133 | } 2134 | }, 2135 | "node_modules/tslib": { 2136 | "version": "2.8.1", 2137 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", 2138 | "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", 2139 | "dev": true, 2140 | "license": "0BSD" 2141 | }, 2142 | "node_modules/typescript": { 2143 | "version": "5.7.2", 2144 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", 2145 | "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", 2146 | "dev": true, 2147 | "license": "Apache-2.0", 2148 | "bin": { 2149 | "tsc": "bin/tsc", 2150 | "tsserver": "bin/tsserver" 2151 | }, 2152 | "engines": { 2153 | "node": ">=14.17" 2154 | } 2155 | }, 2156 | "node_modules/undici-types": { 2157 | "version": "6.20.0", 2158 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", 2159 | "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", 2160 | "dev": true, 2161 | "license": "MIT" 2162 | }, 2163 | "node_modules/uuid": { 2164 | "version": "9.0.1", 2165 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", 2166 | "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", 2167 | "dev": true, 2168 | "funding": [ 2169 | "https://github.com/sponsors/broofa", 2170 | "https://github.com/sponsors/ctavan" 2171 | ], 2172 | "license": "MIT", 2173 | "bin": { 2174 | "uuid": "dist/bin/uuid" 2175 | } 2176 | }, 2177 | "node_modules/v8-compile-cache-lib": { 2178 | "version": "3.0.1", 2179 | "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", 2180 | "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", 2181 | "dev": true, 2182 | "license": "MIT" 2183 | }, 2184 | "node_modules/yn": { 2185 | "version": "3.1.1", 2186 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 2187 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 2188 | "dev": true, 2189 | "license": "MIT", 2190 | "engines": { 2191 | "node": ">=6" 2192 | } 2193 | } 2194 | } 2195 | } 2196 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aws-cdk-loan-broker", 3 | "version": "0.1.0", 4 | "license": "Apache-2.0", 5 | "author": { 6 | "name": "Luis Morales" 7 | }, 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/aws-samples/aws-cdk-loan-broker.git" 11 | }, 12 | "scripts": { 13 | "build": "tsc", 14 | "watch": "tsc -w", 15 | "test": "jest", 16 | "cdk": "cdk" 17 | }, 18 | "devDependencies": { 19 | "@types/node": "22.10.2", 20 | "aws-cdk": "2.173.2", 21 | "ts-node": "^10.9.2", 22 | "typescript": "~5.7.2", 23 | 24 | "@aws-sdk/client-dynamodb": "^3.714.0", 25 | "@aws-sdk/client-sfn": "^3.714.0", 26 | "@aws-sdk/util-dynamodb": "^3.714.0" 27 | }, 28 | "dependencies": { 29 | "aws-cdk-lib": "2.173.2", 30 | "constructs": "^10.4.2", 31 | "source-map-support": "^0.5.21" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /quote-aggregator/app.js: -------------------------------------------------------------------------------- 1 | const { DynamoDBClient, UpdateItemCommand } = require("@aws-sdk/client-dynamodb"); 2 | const { unmarshall } = require("@aws-sdk/util-dynamodb"); 3 | const { SFNClient, SendTaskSuccessCommand } = require("@aws-sdk/client-sfn"); 4 | 5 | const dynamodb = new DynamoDBClient({ apiVersion: "2012-08-10" }); 6 | const sfn = new SFNClient(); 7 | 8 | const mortgageQuotesTable = process.env.MORTGAGE_QUOTES_TABLE; 9 | 10 | 11 | const quoteRequestComplete = (amountQuotes) => 12 | amountQuotes >= 2; 13 | 14 | 15 | const createAppendQuoteUpdateItemCommand = (tableName, id, quote) => 16 | new UpdateItemCommand({ 17 | TableName: tableName, 18 | Key: { Id: { S: id } }, 19 | UpdateExpression: "SET #quotes = list_append(if_not_exists(#quotes, :empty_list), :quote)", 20 | ExpressionAttributeNames: { 21 | "#quotes": "quotes", 22 | }, 23 | ExpressionAttributeValues: { 24 | ":quote": { 25 | L: [ 26 | { 27 | M: { 28 | bankId: { S: quote["bankId"] }, 29 | rate: { N: quote["rate"].toString() }, 30 | }, 31 | }, 32 | ], 33 | }, 34 | ":empty_list": { L: [] }, 35 | }, 36 | ReturnValues: "ALL_NEW", 37 | }); 38 | 39 | 40 | exports.handler = async (event) => { 41 | console.info("Received event:", JSON.stringify(event, null, 4)); 42 | console.info("Processing %d records", event["Records"].length); 43 | 44 | var persistedMortgageQuotes; 45 | for (record of event["Records"]) { 46 | console.debug(record); 47 | 48 | var quote = JSON.parse(record["body"]); 49 | console.info("Persisting quote: %s", JSON.stringify(quote, null, 4)); 50 | 51 | var id = quote["id"]; 52 | var taskToken = quote["taskToken"]; 53 | 54 | var appendQuoteUpdateItemCommand = createAppendQuoteUpdateItemCommand(mortgageQuotesTable, id, quote); 55 | 56 | var dynamodbResponse = await dynamodb.send(appendQuoteUpdateItemCommand); 57 | console.debug(JSON.stringify(dynamodbResponse)); 58 | console.debug(unmarshall(dynamodbResponse.Attributes)); 59 | persistedMortgageQuotes = unmarshall(dynamodbResponse.Attributes); 60 | } 61 | 62 | console.info("Persisted %d quotes", persistedMortgageQuotes.quotes.length); 63 | 64 | if (quoteRequestComplete(persistedMortgageQuotes.quotes.length)) { 65 | console.info("Enough quotes are available"); 66 | var sendTaskSuccessCommand = new SendTaskSuccessCommand({ 67 | taskToken, 68 | output: JSON.stringify(persistedMortgageQuotes.quotes), 69 | }); 70 | 71 | try { 72 | var response = await sfn.send(sendTaskSuccessCommand); 73 | console.debug(response); 74 | } catch (error) { 75 | console.error(error); 76 | } 77 | } else { 78 | console.info("Not enough quotes available yet"); 79 | } 80 | }; 81 | -------------------------------------------------------------------------------- /quote-requester/app.js: -------------------------------------------------------------------------------- 1 | const { DynamoDBClient, GetItemCommand } = require("@aws-sdk/client-dynamodb"); 2 | const { unmarshall } = require("@aws-sdk/util-dynamodb"); 3 | 4 | const dynamodb = new DynamoDBClient({ apiVersion: "2012-08-10" }); 5 | 6 | const mortgageQuotesTable = process.env.MORTGAGE_QUOTES_TABLE; 7 | 8 | exports.handler = async (event) => { 9 | console.info("Received event:", JSON.stringify(event, null, 4)); 10 | var id = event["Id"]; 11 | 12 | var getItemCommand = new GetItemCommand({ 13 | TableName: mortgageQuotesTable, 14 | Key: { Id: { S: id } }, 15 | }); 16 | 17 | var getItemResponse = await dynamodb.send(getItemCommand); 18 | console.debug(JSON.stringify(getItemResponse)); 19 | 20 | if (getItemResponse.Item) { 21 | console.debug(unmarshall(getItemResponse.Item)); 22 | 23 | return unmarshall(getItemResponse.Item); 24 | } else { 25 | return { quotes: [] }; 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2018", 4 | "module": "commonjs", 5 | "lib": [ 6 | "es2018" 7 | ], 8 | "declaration": true, 9 | "strict": true, 10 | "noImplicitAny": true, 11 | "strictNullChecks": true, 12 | "noImplicitThis": true, 13 | "alwaysStrict": true, 14 | "noUnusedLocals": false, 15 | "noUnusedParameters": false, 16 | "noImplicitReturns": true, 17 | "noFallthroughCasesInSwitch": false, 18 | "inlineSourceMap": true, 19 | "inlineSources": true, 20 | "experimentalDecorators": true, 21 | "strictPropertyInitialization": false, 22 | "typeRoots": [ 23 | "./node_modules/@types" 24 | ] 25 | }, 26 | "exclude": [ 27 | "node_modules", 28 | "cdk.out" 29 | ] 30 | } 31 | --------------------------------------------------------------------------------